Angular4 - 3级自定义组件,孙子(ngModelChange)总是看到同一个祖父母

Angular4 - 3 level custom components, grandchild (ngModelChange) always sees same grandparent

我有一个 top-level 组件,在模板中有这个:

  <cw-card-list [cards]="cards">
  </cw-card-list>

当组件加载时,卡片从 API 填充:

  private getCards(): void{
    this._cardService.getCards().subscribe(
      result => {
        this.cards = result;
      }
    );
  }

card-list 组件非常基础:

  <div *ngFor="let card of cards; let i = index">
    <cw-card-list-item
      [card]="card" [index]="i">
    </cw-card-list-item>
  </div>

您可以看到列表中的每张卡片都是 card-list-item child:

中的一个 Input
export class CardListItemComponent implements OnInit, AfterViewInit {
  @Input() card: Card;
  @Input() index: number;
...

最后,每个 list-item 组件也有一个 child:

<cw-checklist-show [template]="card.template" 
</cw-checklist-show>

export class ChecklistShowComponent implements OnInit {
  @Input() template: Template
...

一切正常,显示所有数据。

但是,在这个最终组件中有一个复选框,它绑定到每个 child(一个 TemplateItem)的 属性 'is_completed':

<div *ngFor="let child of template.template_items; let i=index">
          <input id="checkbox-{{i}}" type="checkbox" 
            [ngModel]="child.is_completed"
            (ngModelChange)="onItemIsCompletedChange(i)">
</div>

每次 (ngModelChange) 事件触发时,它总是修改列表中 第一张卡片 的模板的 'is_completed' 属性,而不是一个点击。

为什么会这样?我什至尝试将输出事件连接到 parent 并且控制台记录了模板 - 它总是列出相同的模板,卡片列表数组中的项目 [0]!

但是如果我console.logthis.cards在grandparent,它显示正确的模板附加到每张卡!

数据结构

每张卡片都有一个模板,像这样:

import { Template } from './template';
export class Card {
  constructor() {
  }

  public id: string
  public customer_id: string
  public template: Template
  public follow_up: Date
  public is_new: boolean = true
}

每个模板都有一个 TemplateItem 数组:

import { TemplateItem } from './template-item';

export class Template {
  constructor(
  ) {}

  public id: string
  public account_id: string
  public name: string
  public template_items: Array<TemplateItem>
  public template_type: string
  public status: string
}

每个TemplateItem是这样的:

export class TemplateItem {
  constructor(
  ) {}

  public id: string
  public template_id: string
  public sort: number
  public content: string
  public item_type: string
  public is_completed: boolean = false
}

如果您像我一样习惯于构建模型驱动的表单,这可能不会立即显而易见,但输入的 ID 至关重要。

由于我的输入使用的是 INDEX,这意味着我页面上的复选框没有不同的 ID:

checkbox-{{i}}

这意味着点击它总是会在第一张卡片的复选框(例如 checkbox-0、checkbox-1)上触发事件,因为显然每个孙子 (TemplateItem) 都是一个从 0...n 开始的数组。

所以解决方案是:

      <input id="checkbox-{{child.id}}-{{i}}" type="checkbox" 
        [ngModel]="child.is_completed"
        (ngModelChange)="onItemIsCompletedChange(i)">

现在每个复选框都有一个唯一的 ID,特定于孙子 TemplateItem 的 ID。