【问题标题】:Detect changes in objects inside array in Angular2检测Angular2中数组内对象的变化
【发布时间】:2016-06-15 09:07:56
【问题描述】:

使用 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 的属性之一发生更改时收到通知

【问题讨论】:

  • 你能提供一些代码来展示你的尝试吗?谢谢!

标签: angular typescript


【解决方案1】:

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

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

constructor(private differs:  KeyValueDiffers) {
}

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

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

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 的列表应相应更新。

【讨论】:

  • .create(null) 部分实际上是做什么的?
  • 它用 null 初始化不同的对象。所以diff方法可以确定一阶差分(其实是完整的对象)...
  • 你想把它设置为 null 以外的任何值吗?
  • @ThierryTemplier 您将如何使用现有对象初始化不同的对象? .create 需要 TrackByFunction&lt;V&gt; 作为参数..
  • 当 elt 是一个对象时,如何在循环中编写这一行 this.objDiffer[elt],对于每次迭代 elt.toString() 将等于 [Object, Object] 所以对于每次迭代,您将得到相同的结果。
【解决方案2】:

我在 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);
        });
      }
    });
  }

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

【讨论】:

    猜你喜欢
    • 2021-12-16
    • 2016-04-21
    • 2017-12-06
    • 2016-11-23
    • 1970-01-01
    • 2017-06-03
    • 2023-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多