Angular FormArray选值时如何避免新增行覆盖已选行数据
问题根因
- 全局单例服务被用来存储临时选中的行数据,所有弹窗操作共享同一个存储字段,没有和当前操作的表单行做绑定
- 打开弹窗时没有传入当前行的索引,弹窗关闭后无法定位到需要赋值的目标表单项,读写全局变量必然导致旧值被新值覆盖
- 弹窗关闭逻辑错误:选中行时仅将数据写入全局服务,没有通过
MatDialogRef的close方法把选中值回传给父组件,父组件的弹窗关闭订阅拿不到有效选值数据
修复方案
1. 修改弹窗组件选行逻辑
移除选行时对全局服务的写操作,直接将选中行作为弹窗关闭的返回值传给调用方:
// 弹窗组件TS constructor(private dialogRef: MatDialogRef<ItemDialogComponent>) {} selectedRow(row: any) { // 直接回传选中行数据,无需经过全局服务中转 this.dialogRef.close(row); }
弹窗模板不需要改动,保持原有mat-table和行点击绑定即可。
2. 修改业务组件模板,传入当前行索引
在表单行循环的选值按钮点击事件中,传入当前行的索引值,标记本次弹窗操作对应的目标行:
<!-- 业务组件模板 表单循环部分 --> <tr *ngFor="let ItemRec of ItemRec.controls; let i = index;" [formGroupName]="i"> <td> <!-- 打开弹窗时传入当前行索引i --> <button mat-raised-button color="accent" (click)="openDialog(i)"> <mat-icon>search</mat-icon> </button> </td> <td> <input style="width:200px" class="form-control" formControlName="Item"> </td> </tr>
3. 修改业务组件弹窗逻辑,定向给对应行赋值
调整openDialog方法接收行索引参数,弹窗关闭拿到选值后,直接通过索引定位到FormArray中对应的表单项赋值,完全不依赖全局服务的共享变量:
// 业务组件TS openDialog(rowIndex: number) { this.dialog.open(ItemDialogComponent) .afterClosed() .subscribe(selectedRow => { // 弹窗被直接关闭、未选中任何行时直接终止逻辑 if (!selectedRow) return; // 仅更新当前索引对应的表单项,不会影响其他已选值的行 this.ItemRec.at(rowIndex).patchValue({ Item: selectedRow.ItemCategory.Item // 如需存储选中行的id等其他字段,可在此处追加赋值 }); }); }
4. 清理冗余服务逻辑
删除全局服务中用来临时存储选中行的字段,这类跨组件临时传值场景完全可以通过MatDialog自带的参数传递、返回值能力实现,用全局单例服务存储临时状态非常容易出现数据覆盖、状态错乱的问题。
验证标准
- 任意表单行打开弹窗选值后,仅当前行的输入框会更新为选中值
- 已保存选值的行不会被后续其他行的选值操作覆盖
- 选值过程不依赖全局共享状态,多轮操作后表单数据和界面展示一致
内容的提问来源于stack exchange,提问作者Yan
相关产品推荐
相关产品推荐

