【问题标题】:Template Driven Form doesn't show correct value模板驱动表单未显示正确的值
【发布时间】:2017-12-16 15:21:11
【问题描述】:

当我删除一个地址并添加一个新地址时,我遇到了一个错误。旧地址会被新地址覆盖。

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

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

不是模型错了,不知怎么角度渲染的视图没有正确更新。

查看:

  <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>

组件类:

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

【问题讨论】:

    标签: angular angular-forms


    【解决方案1】:

    一个问题是您对remove 方法的参数和findIndex 中的参数使用相同的名称address。因此,比较 address.id === address.id 会为第一个测试项目返回 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
      );
      ...
    }
    

    或者您可以将索引作为参数传递给removeas suggested by Embrioka


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

    name="location-{{i}}"
    

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

    只要每个address.id 是唯一的,问题就会消失。显然,为不同的项目重复使用相同的名称会阻止 Angular 正确更新输入内容。

    【讨论】:

    • 感谢您的建议,但问题仍然存在。如果您在删除第一个地址后尝试添加地址,则第二个地址将被清除。
    • 问题似乎来自输入元素的名称。如果您将name="location-{{i}}" 更改为name="location-{{address.id}},它可以工作(只要address.id 不同,我假设)。我更新了my stackblitz。我不知道为什么为不同的项目重复使用相同的名称会阻止 Angular 更新内容。
    【解决方案2】:

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

    <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 将是未定义的,因此在 add 方法中只需定义一个 ID 或在查找索引时选择另一个属性!

    【讨论】:

    • 感谢您的建议,但这仍然不能解决主要问题。
    • 凯夫,问题是我提到的。您的 ID 不会被定义。您可以做的是计算数组中最大的 id 并每次使用该 id 创建一个新地址。
    • 我尝试像这样添加一个新地址(出于演示目的): add(){ this.model.addresses.push(new Address(3,'test'));即使使用提供的索引和您提到的删除方法,它也无法修复显示错误。
    • 啊,好吧,我明白你的问题了。其实这是一种很奇怪的行为。
    猜你喜欢
    • 1970-01-01
    • 2014-07-04
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多