Angular 13-无法使用API的数据更新FormGroup
我正在尝试制作一个表格以提交数据,然后用数据填充该表格,以便在以后的阶段进行编辑。该页面可以是新页面,但是无论哪种方式,都可以保持表单布局和验证。
我尝试使用[(ngmodel)]的每个条目,除了可以多个条目的汽车列表之外,所有条目都可以使用。另外,这种方法给了我一条消息,说它被贬低了,这使我认为这不是这样: “看起来您在同一表单字段上与FormControlname .....”
所附的简化页面显示了我所遇到的问题。如何将输入用API的数据预填充?
car.component.html
<div class="center_container">
<mat-card>
<mat-card-content>
<form class="input_form" [formGroup]="formValues">
<p>
<mat-form-field style="padding-right: 10px;" class="two-third-width">
<mat-label>Name</mat-label>
<input
matInput
placeholder="Seller name"
autocomplete="off"
formControlName="name"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Please input">info
</mat-icon>
</mat-form-field>
<mat-form-field class="third-width">
<mat-label>Margin</mat-label>
<input
matInput
placeholder="Seller Margin..."
autocomplete="off"
formControlName="margin"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Please input">info
</mat-icon>
</mat-form-field>
</p>
<table class="full-width" formArrayName="cars">
<tr *ngFor="let _ of cars.controls; index as i; let first=first">
<ng-container [formGroupName]="i">
<td>
<mat-icon (click)="addRow()">add</mat-icon>
</td>
<td>
<mat-icon *ngIf="!first" (click)="removeRow(i)">remove</mat-icon>
</td>
<td class="model">
<mat-form-field class="full-width">
<mat-label>Model</mat-label>
<input
matInput
placeholder="Car model"
autocomplete="off"
formControlName="model"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Please input">info
</mat-icon>
</mat-form-field>
</td>
<td class="state">
<mat-form-field class="full-width">
<mat-label>State</mat-label>
<mat-select formControlName="state">
<mat-option value="new">new</mat-option>
<mat-option value="used">used</mat-option>
</mat-select>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Select it">info
</mat-icon>
</mat-form-field>
</td>
<td class="value">
<mat-form-field class="full-width">
<mat-label>Value</mat-label>
<input
matInput
placeholder="The value..."
autocomplete="off"
formControlName="value"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Some reminder">info
</mat-icon>
</mat-form-field>
</td>
</ng-container>
</tr>
</table>
</form>
</mat-card-content>
<mat-card-actions align="end">
<button mat-raised-button [disabled]="!formValues.valid" (click)="saveSeller()" color="primary">Save seller <i
class="material-icons">send</i></button>
</mat-card-actions>
<mat-card-footer style="margin: 1px;">
<i class="mat-small">create date here</i>
</mat-card-footer>
</mat-card>
</div>
car.component.ts
import {Component, OnInit} from '@angular/core';
import {FormControl, FormGroup, FormArray, Validators} from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-car',
templateUrl: './car.component.html',
styleUrls: ['./car.component.css']
})
export class CarComponent implements OnInit {
formValues = new FormGroup({
cars: new FormArray([
new FormGroup({
model: new FormControl('', [Validators.required]),
value: new FormControl('', [Validators.required]),
state: new FormControl('', [Validators.required])
})
]),
name: new FormControl('', [Validators.required]),
margin: new FormControl('', [Validators.required]),
create_date: new FormControl('')
});
cars = this.formValues.get('cars') as FormArray;
sellerIdFromRoute: any;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const routeParams = this.route.snapshot.paramMap;
this.sellerIdFromRoute = String(routeParams.get('sellerId'));
this.getSeller(this.sellerIdFromRoute);
}
// Form
addRow() {
const group = new FormGroup({
model: new FormControl('', [Validators.required]),
value: new FormControl('', [Validators.required]),
state: new FormControl('', [Validators.required])
});
this.cars.push(group);
}
removeRow(i: number) {
this.cars.removeAt(i);
}
saveSeller(){
// POSTS TO API, THIS WORKS
alert('added/updated seller');
console.log(this.formValues.value);
}
getSeller(id) {
// This is an example response from my API
const example: Seller = {
_id: id,
name: 'Used Ford salesman',
margin: 22,
create_date: {
$date: '2022-05-20T19:45:22.715Z'
},
cars: [
{
model: 'Estate',
value: 12345,
state: 'new'
},
{
model: 'Saloon',
value: 12345,
state: 'used'
},
]
};
console.log(example);
return example;
}
}
export interface Cars {
model: string;
value: number;
state: string;
}
export interface Seller {
_id: string;
name: string;
margin: number;
create_date: any;
cars: Array<Cars>;
}
I am trying to make a form to submit data, then populate that form with data in order to edit it on a later stage. The page can be new page, but it would be nice to keep the form layout and validation either way.
I have tried using [(ngModel)] for each entry that works for everything except the list of cars that can multiple entries. Also this method gives me a message saying it's deprecated making me think that is not the way:"It looks like you're using ngModel on the same form field as formControlName....."
Attached is a simplified page that show the issue I am having. How do I prefill the inputs with the data from the API ?
car.component.html
<div class="center_container">
<mat-card>
<mat-card-content>
<form class="input_form" [formGroup]="formValues">
<p>
<mat-form-field style="padding-right: 10px;" class="two-third-width">
<mat-label>Name</mat-label>
<input
matInput
placeholder="Seller name"
autocomplete="off"
formControlName="name"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Please input">info
</mat-icon>
</mat-form-field>
<mat-form-field class="third-width">
<mat-label>Margin</mat-label>
<input
matInput
placeholder="Seller Margin..."
autocomplete="off"
formControlName="margin"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Please input">info
</mat-icon>
</mat-form-field>
</p>
<table class="full-width" formArrayName="cars">
<tr *ngFor="let _ of cars.controls; index as i; let first=first">
<ng-container [formGroupName]="i">
<td>
<mat-icon (click)="addRow()">add</mat-icon>
</td>
<td>
<mat-icon *ngIf="!first" (click)="removeRow(i)">remove</mat-icon>
</td>
<td class="model">
<mat-form-field class="full-width">
<mat-label>Model</mat-label>
<input
matInput
placeholder="Car model"
autocomplete="off"
formControlName="model"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Please input">info
</mat-icon>
</mat-form-field>
</td>
<td class="state">
<mat-form-field class="full-width">
<mat-label>State</mat-label>
<mat-select formControlName="state">
<mat-option value="new">new</mat-option>
<mat-option value="used">used</mat-option>
</mat-select>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Select it">info
</mat-icon>
</mat-form-field>
</td>
<td class="value">
<mat-form-field class="full-width">
<mat-label>Value</mat-label>
<input
matInput
placeholder="The value..."
autocomplete="off"
formControlName="value"
>
<mat-icon class="mat-primary" matSuffix
matTooltip="[REQUIRED] Some reminder">info
</mat-icon>
</mat-form-field>
</td>
</ng-container>
</tr>
</table>
</form>
</mat-card-content>
<mat-card-actions align="end">
<button mat-raised-button [disabled]="!formValues.valid" (click)="saveSeller()" color="primary">Save seller <i
class="material-icons">send</i></button>
</mat-card-actions>
<mat-card-footer style="margin: 1px;">
<i class="mat-small">create date here</i>
</mat-card-footer>
</mat-card>
</div>
car.component.ts
import {Component, OnInit} from '@angular/core';
import {FormControl, FormGroup, FormArray, Validators} from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-car',
templateUrl: './car.component.html',
styleUrls: ['./car.component.css']
})
export class CarComponent implements OnInit {
formValues = new FormGroup({
cars: new FormArray([
new FormGroup({
model: new FormControl('', [Validators.required]),
value: new FormControl('', [Validators.required]),
state: new FormControl('', [Validators.required])
})
]),
name: new FormControl('', [Validators.required]),
margin: new FormControl('', [Validators.required]),
create_date: new FormControl('')
});
cars = this.formValues.get('cars') as FormArray;
sellerIdFromRoute: any;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const routeParams = this.route.snapshot.paramMap;
this.sellerIdFromRoute = String(routeParams.get('sellerId'));
this.getSeller(this.sellerIdFromRoute);
}
// Form
addRow() {
const group = new FormGroup({
model: new FormControl('', [Validators.required]),
value: new FormControl('', [Validators.required]),
state: new FormControl('', [Validators.required])
});
this.cars.push(group);
}
removeRow(i: number) {
this.cars.removeAt(i);
}
saveSeller(){
// POSTS TO API, THIS WORKS
alert('added/updated seller');
console.log(this.formValues.value);
}
getSeller(id) {
// This is an example response from my API
const example: Seller = {
_id: id,
name: 'Used Ford salesman',
margin: 22,
create_date: {
$date: '2022-05-20T19:45:22.715Z'
},
cars: [
{
model: 'Estate',
value: 12345,
state: 'new'
},
{
model: 'Saloon',
value: 12345,
state: 'used'
},
]
};
console.log(example);
return example;
}
}
export interface Cars {
model: string;
value: number;
state: string;
}
export interface Seller {
_id: string;
name: string;
margin: number;
create_date: any;
cars: Array<Cars>;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
正如Angular警告您的那样,混合
模板驱动的表单
和反应性形式
这是一种不好的做法官方Angular Doc )。要用反应性式(您的情况)填充表单控制值,您必须在组件初始化中设置值。您可以同时设置所有FormGroup值:
使用
PatchValue
方法,而不是setValue
如果您不想初始化所有FormControls,则在此处。或者,也可以直接在FormControl上设置值:
我个人更喜欢在不同领域中分别管理FormControls,它为您提供了更大的灵活性和更多的控制,以充分利用反应性表单API的丰富性。
As Angular warns you, it's a bad practice to mix
Template driven form
andReactive form
this can lead to a lot of unwanted behaviours (you can get a lot of informations about Angular forms in the official Angular doc).To fill form control values with Reactive form (your case), you have to set values at your component initialization. You can set all formGroup values at the same time :
Use
patchValue
method instead ofsetValue
here if you don't want to initialise all formControls.Or, it's also possible to set value directly on formControl :
Personally, I prefer managing formControls separately in different fields, it gives you more flexibility and more control in order to take full advantage of the richness of the reactive forms api.
不确定这是否是最好的方法,但最终使用了以下方式:
Not sure if this is the best way, but ended up using this: