Angular 5如何为嵌套FormGroup的FormArray初始化赋值现有数据
解决Angular表单初始化时将现有数组数据填充到FormArray的问题
你的代码里主要有几个问题导致无法正确填充数据,我来一步步帮你修正:
问题分析
- 重复初始化表单:在
ngOnInit里你多次重新创建requirementForm,这会覆盖之前的表单实例,导致后续的操作无法正确绑定到模板上的表单。 - FormArray控件访问错误:你尝试通过
this.requirementForm.controls['itemRows'].controls['itemname']设置值,但itemRows是一个FormArray,它的controls是数组,不是键值对对象,不能直接用['itemname']访问内部控件。 - 初始行冗余:你一开始就添加了一个空行,这会导致最终表单多一行空输入框(如果后端有2条数据,会变成3行)。
修正后的TypeScript代码
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormBuilder, FormArray } from '@angular/forms'; import { StoreService } from './your-store-service-path'; // 替换成你的实际路径 @Component({ selector: 'app-your-component', templateUrl: './your-component.html', }) export class YourComponent implements OnInit { public product: any; public requirementForm: FormGroup; constructor(private _store: StoreService, private fb: FormBuilder) { this.createForm(); // 在构造函数里只初始化一次表单 } // 简化FormArray的访问,方便模板使用 get itemRows(): FormArray { return this.requirementForm.get('itemRows') as FormArray; } createForm() { this.requirementForm = this.fb.group({ itemRows: this.fb.array([]) // 初始化空的FormArray,后续从后端数据填充 }); } ngOnInit() { this._store.ownersingleView(this.pid).subscribe((data: any) => { this.product = data; const itemRowsArray = this.itemRows; // 先清空数组(避免重复添加,可选但推荐) itemRowsArray.clear(); // 遍历后端返回的require数组,为每个item创建表单行并赋值 data.require.forEach((requireItem: any) => { // 直接创建带有初始值的FormGroup并添加到FormArray itemRowsArray.push( this.fb.group({ itemname: [requireItem.item] }) ); // 如果你想保留initItemRows方法,也可以这么写: // const newRow = this.initItemRows(); // newRow.patchValue({ itemname: requireItem.item }); // itemRowsArray.push(newRow); }); }); } initItemRows() { return this.fb.group({ itemname: [''] }); } addNewRow() { this.itemRows.push(this.initItemRows()); } deleteRow(index: number) { if (this.itemRows.length > 1) { this.itemRows.removeAt(index); } } }
优化后的HTML代码
主要优化了*ngFor里的FormArray访问,利用我们定义的itemRows getter,让代码更简洁:
<div class="row"> <div class="col s12 m12 l12"> <form [formGroup]="requirementForm"> <div formArrayName="itemRows"> <div class="item_x"> <div [@itemAnim]="true" class="item_in" *ngFor="let itemrow of itemRows.controls; let i=index" [formGroupName]="i"> <div class="i-in"> <div class="requirement_item"> <h6>نیازمندی #{{ i + 1 }}</h6> <div class="form-group"> <label>نام آیتم</label> <input formControlName="itemname" class="form-control"> </div> </div> <div class="requirement_x"> <div class="requirment_del"> <div class="rdc"> <button *ngIf="itemRows.length > 1" (click)="deleteRow(i)" mat-mini-fab=""> <i class="mdi mdi-delete"></i> </button> </div> </div> </div> </div> </div> </div> </div> <div class="action"> <div class="action_i"> <div class="ac_in"> <button mat-mini-fab color="primary" (click)="addNewRow()"> <i class="mdi mdi-plus"></i> </button> </div> </div> </div> </form> </div> </div>
核心修改点说明
- 只初始化一次表单:在构造函数里调用
createForm(),避免后续重复创建表单实例。 - 使用getter简化FormArray访问:
itemRowsgetter让模板和TS代码里访问FormArray更简洁,也避免了重复的类型转换。 - 正确填充数据:遍历后端数据时,直接为每个item创建带初始值的FormGroup,或者先创建空行再用
patchValue赋值,确保每个输入框都能正确绑定对应的数据。 - 删除冗余初始行:不再在初始化时添加空行,完全由后端数据生成表单行,避免多余的空输入框。
这样修改后,你的表单就能正确加载后端返回的item数据,每个数据对应一个输入框,同时新增、删除行的功能也能正常工作。
内容的提问来源于stack exchange,提问作者devmrh
相关产品推荐
相关产品推荐

