检测Angular2中数组内对象的更改

时间:2016-03-02 13:23:22

标签: angular typescript

使用Angular 2和打字稿。我有一个数组,我使用DoCheck和IterableDiffer来监听我的代码中的更改。当数组被更改时,我会收到通知,但是当数组中某个对象内的属性发生变化时,我就不会收到通知。 我尝试使用KeyValueDiffer,但它不起作用。 我想也许我需要使用" _differs.find"不同。 有什么想法吗?

@Component({
    selector: 'test'
})
@View({
    template: `
    <div>hello!</div>`
})
export class MyComponent implements DoCheck {

private _differ: IterableDiffer;
private _differ2: KeyValueDiffer;
_myItems: MyItem[];
@Input()
set myItems(value: MyItem[]) {
    this._myItems = value;

    if (!this._differ && value) {
        this._differ = this._iterableDiffers.find([]).create(null);
    }
    if (!this._differ2 && value) {
        this._differ2 = this._differs.find(this._myItems).create(null);
    }
}
get myItems() {
    return this._myItems;
}

constructor(private _iterableDiffers: IterableDiffers, private _differs: KeyValueDiffers, private _myService: MyService) {
    this.myItems = _myService.getItems();
}

ngDoCheck() {

    var changes = this._differ.diff(this._myItems);

    if (changes) {
        changes.forEachAddedItem((record) => {
            console.log('added ' + record.item);
        });
        changes.forEachRemovedItem((record) => {
            console.log('removed ' + record.item);
        });
    }

    var changes2 = this._differ2.diff(this._myItems);
    if (changes2) {
        changes2.forEachChangedItem(
            (record) => {
                    console.log(record.key + "," + record.currentValue);
                }
            });
    }
  }
}

无法通知MyItem

的某个属性的更改

2 个答案:

答案 0 :(得分:21)

实际上,您需要检查列表中不是列表本身的每个对象的差异。 KeyValueDiffer必须应用于不在数组上的对象。

您可以为数组元素初始化包含所有这些KeyValueDiffer实例的对象:

constructor(private differs:  KeyValueDiffers) {
}

ngOnInit() {
  this.objDiffer = {};
  this.list.forEach((elt) => {
    this.objDiffer[elt] = this.differs.find(elt).create(null);
  });
}

ngDoCheck中,您需要迭代differ以检查是否有更改(对于数组的每个项目):

ngDoCheck() {
  this.list.forEach(elt => {
    var objDiffer = this.objDiffer[elt];
    var objChanges = objDiffer.diff(elt);
    if (objChanges) {
      objChanges.forEachChangedItem((elt) => {
        if (elt.key === 'prop1') {
          this.doSomethingIfProp1Change();
        }
      });
    }
  });
}

请参阅此plunkr:http://plnkr.co/edit/JV7xcMhAuupnSdwrd8XB?p=preview

请注意,我跳过了数组的更改检测...但两者都可以并行完成。此外,当添加/删除元素时,KeyValueDiffers列表应相应更新。

答案 1 :(得分:0)

我在Thierry Templiers的答案中找到了灵感,但它对我不起作用-我对其进行了修改,最终得到了以下解决方案:

您有这个私有变量:

 private objDiffers: Array<KeyValueDiffer<string, any>>;

您要观看数组中的每个元素。在这种情况下,数组类型为Array。构造函数应如下所示:

  constructor(
    private differs: KeyValueDiffers) {
    this.itemGroups = new Array<ItemGroup>();
    this.differ = this.differs.find(this.itemGroups).create();
  }

ngOninit像这样:

  public ngOnInit(): void {
    this.objDiffers = new Array<KeyValueDiffer<string, any>>();
    this.itemGroups.forEach((itemGroup, index) => {
      this.objDiffers[index] = this.differs.find(itemGroup).create();
    });
  }

和ngDoCheck这样:

ngDoCheck(): void {
    this.itemGroups.forEach((itemGroup, index) => {
      const objDiffer = this.objDiffers[index];
      const objChanges = objDiffer.diff(itemGroup);
      if (objChanges) {
        objChanges.forEachChangedItem((changedItem) => {
          console.log(changedItem.key);
        });
      }
    });
  }

现在,您会注意到,每次数组中的一项发生更改时,您都会获得一个控制台日志,其中包含该项以及已更改的属性。