Angular NgForm动态增删输入项后原有输入内容丢失问题
问题根因
*ngFor默认采用数组索引作为节点跟踪标识,删除数组靠前位置的元素后,后续元素的索引会整体前移,Angular会错误复用DOM节点,导致数据绑定关系错乱。- 输入框的
name属性采用索引拼接生成,索引变动后表单控件与绑定值的对应关系断裂,原有输入内容会被清空。
修复方案
- 给答案模型增加唯一ID字段,新增项时生成唯一标识,替代索引作为全局唯一跟踪依据
- 给
*ngFor配置trackBy函数,按唯一ID跟踪列表节点,避免DOM错误复用 - 输入框的
name属性改为用唯一ID拼接,保证表单控件绑定关系稳定
完整修改后代码
模板代码(app.component.html)
<form #form="ngForm" (ngSubmit)="submit()" style="display: flex; justify-content: center;flex-direction:column;align-items: center; padding: 100px 0;"> <div *ngFor="let ans of task.questionAnswerModelList; let i = index; trackBy: trackByAnswerId"> <input [(ngModel)]="ans.answerText" [required]="true" name="{{'answerText' + ans.id}}" style="height: 50px;margin-bottom: 10px;"> <span style="background-color: red;" (click)="remove(i)">X</span> <span>{{ans.answerText}}</span> </div> <button type="submit" style="width: 100px; color: green;">Submit</button> </form> <div style="display: flex; justify-content: center;"> <button type="button" (click)="addAnswers()" style="background-color: aqua; color: white; border: none;padding: 1rem;">Add Answers</button> </div>
组件代码(app.component.ts)
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core'; import { NgForm } from '@angular/forms'; export interface QuestionAnswerModelInterface { id: number; answerText?: string; correct?: boolean; } @Component({ selector: 'app-root', templateUrl: './app.component.html', changeDetection:ChangeDetectionStrategy.OnPush }) export class AppComponent{ @ViewChild('form', {static: false}) public form!: NgForm; // 自增ID生成器,保证每个答案项ID全局唯一 private nextAnswerId = 3; public task = { question: '', questionAnswerModelList: [ { id: 1, answerText: '', }, { id: 2, answerText: '', }, ], }; addAnswers(){ this.task.questionAnswerModelList.push({ id: this.nextAnswerId++, answerText:'' }) } remove(i:number){ if(this.task.questionAnswerModelList.length > 2 ){ this.task.questionAnswerModelList.splice(i,1) } } submit(){ console.log(this.form) } // ngFor跟踪函数,按ID匹配节点 trackByAnswerId(index: number, item: QuestionAnswerModelInterface): number { return item.id; } }
内容的提问来源于stack exchange,提问作者medzvre gena
相关产品推荐
相关产品推荐

