[英]Angular Reactive Forms with FormArray inside a nested FormGroup
[英]FormGroup inside FormArray in Angular 2 Reactive Forms
我未能让 Angular 2 反应式表单工作,其中FormGroup嵌套在FormArray 中。 有人可以告诉我我的设置有什么问题吗?
为简洁起见,省略了代码中不相关的部分。
以下是我的组件
orderForm: FormGroup = this.fb.group({
id: [''],
store: ['', Validators.required],
//The part related to the error
order_lines: this.fb.array([
this.fb.group({
id: [''],
order_id: [],
product_id: [],
description: ['', Validators.required],
unit_price: ['', Validators.required],
discount: [0],
units: [1, Validators.required],
line_total: ['', Validators.required]
})
])
});
constructor(private fb: FormBuilder) { }
//Order instance is passed from elsewhere in the code
select(order: Order): void {
this.orderForm.reset(order)
}
传递给 select 方法的Order
实例是这样的:
{
"id": 20,
"store": "Some Store",
"order_lines": [
{
"id": 6,
"order_id": 20,
"product_id": 1,
"description": "TU001: Polka dots",
"unit_price": "1000.00",
"discount": "100.00",
"units": 2,
"line_total": "1900.00"
},
{
"id": 7,
"order_id": 20,
"product_id": 2,
"description": "TU002: Polka dots",
"unit_price": "500.00",
"discount": "0.00",
"units": 1,
"line_total": "500.00"
}
]
}
视图模板如下所示。
<form [formGroup]="orderForm">
<input type="number" formControlName="id">
<input type="text" formControlName="store">
<div formArrayName="order_lines">
<div *ngFor="let line of orderForm.get('order_lines'); let i=index">
<div [formGroupName]="i">
<input type="text" [formControlName]="product_id">
<input type="text" [formControlName]="description">
<input type="number" [formControlName]="units">
<input type="number" [formControlName]="unit_price">
<input type="number" [formControlName]="line_total">
</div>
</div>
</div>
</form>
这个设置给了我一个控制台错误**无法在 order_lines -> 0 -> ** 找到控制。 我想知道我做错了什么。
我可以让它与 order_lines FormArray 中的简单FormControl一起使用。 但它无法给定的错误时,FormGroup是FormArray内部使用。
你能帮我解决这个问题吗?
而不是使用form.get
更好地使用如下控件 -
<form [formGroup]="orderForm">
<input type="number" formControlName="id">
<input type="text" formControlName="store">
<div formArrayName="order_lines">
<div *ngFor="let line of orderForm.controls.order_lines.controls; let i=index">
<div [formGroupName]="i">
<input type="text" formControlName="product_id">
<input type="text" formControlName="description">
<input type="number" formControlName="units">
<input type="number" formControlName="unit_price">
<input type="number" formControlName="line_total">
</div>
</div>
</div>
</form>
你所缺少的——
.control
去年* ngFor的遍历控制。[formControlName]
替换为formControlName
@Johna,补充我的回答:
你有两个功能
buildForm(data:any):FormGroup
{
return data?this.fb.group({
id: [data.id?data.id:''],
store: [data.store?data.store:'', Validators.required],
order_lines:this.fb.array(this.buildArrayControl(data.order_lines?data.order_lines:null))
})
:
this.fb.group({
id: [''],
store: ['', Validators.required],
order_lines:this.fb.array(this.buildArrayControl(null))
})
}
buildArrayControl(data:any[]|null):FormGroup[]
{
return data?
data.map(x=>{
return this.fb.group({
id: [x.id?x.id:''],
order_id: [x.order_id?x.order_id:''],
product_id: [x.product_id?x.product_id:''],
description: [x.description?x.description:'', Validators.required],
unit_price: [x.unit_price?x.unit_price:'', Validators.required],
discount: [x.discount?x.discount:0],
units: [x.units?x.units:1, Validators.required],
line_total: [x.line_total?x.line_total:'', Validators.required]
})
})
:
[this.fb.group({
id: [''],
order_id: [],
product_id: [],
description: ['', Validators.required],
unit_price: ['', Validators.required],
discount: [0],
units: [1, Validators.required],
line_total: ['', Validators.required]
})
]
}
然后你可以做,例如
this.orderForm = this.buildForm(
{
id:'112',
store:'22655',
order_lines:[{description:1222,....},{description:1455,...}]
}
)
//or
this.orderForm=this.buildForm(null);
您可以使用 *ngFor 内联移动 formArrayName 并在 ngFor 中包含 .controls,因为我们正在循环表单控件。
<div>
<div formArrayName="order_lines" *ngFor="let line of orderForm.get('order_lines').controls; let i=index">
<div [formGroupName]="i">
<input type="text" [formControlName]="product_id">
<input type="text" [formControlName]="description">
<input type="number" [formControlName]="units">
<input type="number" [formControlName]="unit_price">
<input type="number" [formControlName]="line_total">
</div>
</div>
</div>
我知道 OP 的问题已经得到解答,但我想发布我的问题的解决方案,由于 OP 的问题和以上答案,我解决了这个问题。
我被要求创建一个动态表单(问卷),但在实现嵌套的 Angular 动态表单时遇到了一些问题。
生成的动态表单可以预先填充多个条目,或者您可以向空列表中添加更多字段,或两者兼而有之。
我的用例创建了一个汽车检查表,起始数组上的每个项目都是操作员的“待办事项”任务。
Angular 9 + Material + Bootstrap。
以下代码将更好地阐明:
/* Component Typescript */ constructor( private formBuilder: FormBuilder ) { } arrayTitoli = [ "TASK1", "TASK2", "TASK3", "TASK4", "TASK5", ] addTaskField(value) { this.array.push( this.formBuilder.group({ titolo: value, checkbox: false, noteAggiuntive: "" }) ) } get titoliArray(){ let array = []; for(let i = 0;i <this.arrayTitoli.length;i++){ array.push( this.formBuilder.group({ titolo: this.arrayTitoli[i], checkbox: false, noteAggiuntive: "" }) ) } return array; } angForm: FormGroup = this.formBuilder.group({ array: this.formBuilder.array(this.titoliArray) }); get array(): FormArray { return this.angForm.get('array') as FormArray; } onFormSubmit(): void { console.log(this.angForm.value) }
<!-- Component HTML --> <div class="p-2"> <form [formGroup] = "angForm" (ngSubmit)="onFormSubmit()"> <div> <button type="submit" class="btn btn-primary">Send</button> </div> <div formArrayName="array"> <div *ngFor="let line of array.controls; index as idx;"> <div [formGroupName]="idx"> <mat-grid-list style="text-align: center!important;" [cols]="3" rowHeight="13vh" (window:resize)="onResize($event)"> <mat-grid-tile style="font-weight: bold;font-size: smaller;" class="col-md-4 col-xs-4" colspan="1"> {{line.controls['titolo'].value}} </mat-grid-tile> <mat-grid-tile class="col-md-4" colspan="1"> <mat-checkbox formControlName="checkbox" #check color="primary"> <!--<button *ngIf="!mobile" type="button" (click)="check.toggle()" class="btn btn-{{check.checked ? 'success' : 'danger'}} btn-sm" >SPUNTA</button>--> </mat-checkbox> <mat-form-field [style.maxWidth.%]="mobile ? '70' : '100'" style="margin-left: 10%;"> <mat-label *ngIf="!mobile">Note aggiuntive</mat-label> <mat-label *ngIf="mobile">Note</mat-label> <textarea formControlName="noteAggiuntive" matInput value='' cdkTextareaAutosize #autosize="cdkTextareaAutosize" cdkAutosizeMinRows="1" cdkAutosizeMaxRows="5"></textarea> </mat-form-field> </mat-grid-tile> </mat-grid-list> <hr> </div> </div> </div> </form> <div> <mat-form-field> <input type="text" #newTask matInput> </mat-form-field> <span class="px-2"> <button type="button" class="btn btn-primary" (click)="addTaskField(newTask.value)">Create</button> </span> </div> </div>
希望它可以有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.