模板驱动表单未显示正确的值

Template Driven Form doesn't show correct value

我在删除地址并添加新地址时遇到错误。以前的地址被新地址覆盖。

我创建了一个小型演示应用程序来展示我的问题:

github: https://github.com/kolomu/HeroDemo
堆栈闪电战:https://stackblitz.com/edit/angular-gitter-5o6ydi

并不是模型有问题,而是 angular 渲染的视图没有正确更新。

查看:

  <form #heroForm="ngForm">

    <div class="form-group">
      <div class="addresses" *ngFor="let address of model.addresses; let i=index">
        <label for="address-{{i}}">Address {{i}}</label>
        <input type="text" class="form-control" [(ngModel)]="address.location" name="location-{{i}}">
        <button class="btn btn-danger" (click)="remove(address)">Remove Address</button>
      </div>
    </div>

    <button class="btn btn-primary" (click)="add()">Add Address</button>

  </form>

组件Class:

export class HeroFormComponent {

  model = new Hero(18, 'Dr IQ', [new Address(1,'main','Earth'), new Address(9001,'sub','Moon')]);

  remove(address) {
    const index = this.model.addresses.findIndex(
      address => address.id === address.id
    );

    this.model.addresses.splice(index, 1);
  }

  add(){
    this.model.addresses.push(new Address());
  }

}

数据模型:

export class Address {
    constructor(public id?: number, public type?:string, public location?: string) { }
}


export class Hero {

    constructor(
      public id: number,
      public name: string,
      public addresses: Address[]
    ) {  }

}

展示问题的 GIF 图像: https://gfycat.com/DelightfulSpiffyBetafish

一个问题是您对 remove 方法的参数和 findIndex 中的参数使用了相同的名称 address。结果,第一个项目的比较 address.id === address.id returns true 因为它将项目与自身进行比较。

remove(address) {
  const index = this.model.addresses.findIndex(
    address => address.id === address.id          <-- Always true!
  );
  ...
}

您应该使用不同的名称,例如 findIndex 中的参数 _address(如 this stackblitz 所示):

remove(address) {
  const index = this.model.addresses.findIndex(
    _address => _address.id === address.id
  );
  ...
}

或者您可以将索引作为参数传递给 remove


在您的代码示例中,当您在删除第一个地址后添加新地址时,两个字段显示相同的数据(新地址的值)。这很奇怪,因为模板和代码中的一切看起来都很好。根据我的测试,问题出在新输入元素的名称与之前用于其他元素的名称相同这一事实。在您的模板中,如果您替换:

name="location-{{i}}"

name="location-{{address.id}}"

只要每个 address.id 都是唯一的,问题就消失了。显然,为不同的项目重复使用相同的名称会阻止 Angular.

正确更新输入内容

不要传递整个地址,只传递索引:

<div class="form-group">
      <div class="addresses" *ngFor="let address of model.addresses; let i=index">
        <label for="address-{{i}}">Address {{i}}</label>
        <input type="text" class="form-control" [(ngModel)]="address.location" name="location-{{i}}">
        <button class="btn btn-danger" (click)="remove(i)">Remove Address</button>
      </div>
</div>

并且在 ts:

remove(index) {
    this.model.addresses.splice(index, 1);
}

有了这个解决方案,您甚至不必找到索引。

您的解决方案存在问题,之前的评论者提到的以及您的 ID 都将是未定义的,因此在添加方法中只需定义一个 ID 或在查找索引时选择另一个 属性!