ngFor循环中输入框输入同步变更如何修复及ngFor数据绑定方法
问题描述
使用Angular的ngFor循环生成输入框时,在任意一个输入框输入内容,其余所有输入框内容都会同步变更,异常效果如下:
原始代码
HTML代码
<mat-expansion-panel class="childPanel" [expanded]="true" hideToggle disabled style=" background:#F2EDFF;" *ngFor="let i of listSousCategorie"> <div class="childPanel_body2 mat-badge-large" fxLayout="row" fxFlex fxLayoutAlign="start center"> <div style="padding-left:1em" fxFlex="grow" >{{i.libelle}} {{i.id}}</div> <mat-form-field> <form [formGroup]="form" (ngSubmit)="onSubmit(i.id)"> <mat-label>Note</mat-label> <input type="text" matInput formControlName="Note" [(ngModel)]="Note" > </form> </mat-form-field> </div> </mat-expansion-panel>
TS代码
Note:string; ngOnInit() { this.form = this.formBuilder.group({ Note: [''], }); } onSubmit(id:number) { let obj = this.form.value; obj.Note = this.Note; console.log(this.Note) this.LExamenSousCategorieService.updateSouCategorie(obj,id).then(res => { }) }
问题原因
- 所有循环生成的输入框都共享同一个全局Note变量和同一个FormGroup实例,双向绑定的数据源完全一致,修改一个自然会同步到所有输入框
- 同时使用
formControlName和ngModel属于Angular不推荐的混合用法,v6+版本默认会抛出警告,也容易引发逻辑冲突
修复方案
提供两种常用修复方案,可根据业务场景选择:
方案一:绑定到单条数据属性(适合简单无校验场景)
无需使用响应式表单,直接将输入值绑定到每个循环项自身的属性,每个项维护独立的输入值:
TS修改
// 删除全局Note变量声明和全局form的初始化代码 onSubmit(id:number, currentNote: string) { const obj = { Note: currentNote }; console.log(currentNote); this.LExamenSousCategorieService.updateSouCategorie(obj,id).then(res => {}); }
HTML修改
<mat-expansion-panel class="childPanel" [expanded]="true" hideToggle disabled style=" background:#F2EDFF;" *ngFor="let i of listSousCategorie"> <div class="childPanel_body2 mat-badge-large" fxLayout="row" fxFlex fxLayoutAlign="start center"> <div style="padding-left:1em" fxFlex="grow" >{{i.libelle}} {{i.id}}</div> <mat-form-field> <form (ngSubmit)="onSubmit(i.id, i.note)"> <mat-label>Note</mat-label> <input type="text" matInput [(ngModel)]="i.note" [ngModelOptions]="{standalone: true}"> </form> </mat-form-field> </div> </mat-expansion-panel>
方案二:使用FormArray(适合需要表单校验的复杂场景)
用FormArray为每个循环项创建独立的FormGroup,符合响应式表单最佳实践:
TS修改
noteFormArray: FormArray; ngOnInit() { // 为每个列表项生成独立的FormGroup存入FormArray this.noteFormArray = this.formBuilder.array( this.listSousCategorie.map(() => this.formBuilder.group({ Note: [''] }) ) ); } onSubmit(id:number, index: number) { const obj = this.noteFormArray.at(index).value; console.log(obj.Note); this.LExamenSousCategorieService.updateSouCategorie(obj,id).then(res => {}); }
HTML修改
<mat-expansion-panel class="childPanel" [expanded]="true" hideToggle disabled style=" background:#F2EDFF;" *ngFor="let i of listSousCategorie; let index = index"> <div class="childPanel_body2 mat-badge-large" fxLayout="row" fxFlex fxLayoutAlign="start center"> <div style="padding-left:1em" fxFlex="grow" >{{i.libelle}} {{i.id}}</div> <mat-form-field> <form [formGroup]="noteFormArray.at(index)" (ngSubmit)="onSubmit(i.id, index)"> <mat-label>Note</mat-label> <input type="text" matInput formControlName="Note"> </form> </mat-form-field> </div> </mat-expansion-panel>
注意事项
- 不要混合使用
formControlName和ngModel,二者选其一即可,避免逻辑冲突 - 循环生成的表单控件必须对应独立的数据源,不能所有项共享同一个全局变量或同一个FormGroup实例
内容的提问来源于stack exchange,提问作者drnwork
相关产品推荐
相关产品推荐

