You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 14中*ngFor添加新对象后旧对象值不显示问题求助

问题解决思路与方案

问题根源分析

  1. 旧值消失问题:你用contact.contactEmail作为ngModelGroup的名称,初始添加的联系人邮箱都是空字符串,导致多个表单控件组的名称重复,Angular表单无法正确识别每个控件组的归属,添加新联系人后就会出现值丢失的情况。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:42:05