Angular 14中*ngFor添加新对象后旧对象值不显示问题求助
问题解决思路与方案
问题根源分析
- 旧值消失问题:你用
contact.contactEmail作为ngModelGroup的名称,初始添加的联系人邮箱都是空字符串,导致多个表单控件组的名称重复,Angular表单无法正确识别每个控件组的归属,添加新联系人后就会出现值丢失的情况。 - trackBy导致失焦问题:你把
contactEmail作为trackBy的标识,当编辑邮箱时,这个标识值发生变化,Angular会判定当前组件对应的项已被替换,销毁旧组件并创建新组件,自然就失去了输入焦点。
修复方案
1. 改用索引作为trackBy标识
把trackBy的返回值改成数组的索引,索引是唯一且稳定的,不会随表单值变化而改变,这样编辑时组件不会被销毁重建,也就不会失焦:
// 父组件修改trackBy方法 trackBy(index: number): number { return index; }
2. 修复ngModelGroup命名冲突
用当前项的索引作为ngModelGroup的名称,确保每个表单组的唯一性:
<!-- 子组件模板修改ngModelGroup --> <fieldset [ngModelGroup]="index">
3. 移除不必要的事件同步(可选优化)
因为你已经用了[(ngModel)]双向绑定,子组件直接修改的是父组件传入的contact对象(引用类型),值会自动同步到父组件,所以可以删掉子组件的changeContactName、changeContactEmail事件,以及父组件的editContact方法,简化代码:
子组件简化后:
@Component({ ... viewProviders: [{provide: ControlContainer, useExisting: NgForm}], }) export class AddContactComponent { @Input() index = 0; @Input() contact!: Contact; @Output() deleteContactTask = new EventEmitter<number>(); clickDeleteContact() { this.deleteContactTask.emit(this.index); } }
子模板简化后:
<fieldset [ngModelGroup]="index"> <div> <label for="contactName">Name:</label> <input type="text" name="contactName" required #name="ngModel" [(ngModel)]="contact.contactName" > <p *ngIf="name.touched && !name.valid"> Please enter contact name </p> </div> <div> <label for="contactEmail">Email:</label> <input type="email" name="contactEmail" required email #email="ngModel" [(ngModel)]="contact.contactEmail" > <p *ngIf="email.touched && !email.valid"> Please enter a valid email </p> </div> </fieldset>
这样修改后,既解决了添加新联系人后旧值消失的问题,也不会出现输入框频繁失焦的情况,同时代码更简洁。
内容的提问来源于stack exchange,提问作者Liran_T
相关产品推荐
相关产品推荐

