君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

Angular2/4のngOnChangesはオブジェクトプロパティが変わったことを検知しない〜Lifecycle HooksのngOnChages, ngDoCheckの違い〜

ngOnChangesを使って、子に渡したプロパティが変わったことを検知する

コンポーネント

/** app.component.ts */
export class AppComponent {
  public datas = 1;
  onClick()
  {
    this.datas ++;
  }
}
<!-- app.component.html -->
<button (click)="onClick()">押してください</button>
<app-child [parentProperty]='datas'></app-child>

コンポーネント

<!-- child/child.component.ts -->
export class ChildComponent implements OnInit, OnChanges {
  @Input() parentProperty;
  constructor() { } 
  ngOnInit() {
  }
  ngOnChanges() {
    console.log('changes');
  }
}

結果

clickするたび、changesが表示される。

ngOnChangesを使って、子に渡したオブジェクトのプロパティが変わったことを検知する

今度は子Componentにオブジェクトをわたして、

そのオブジェクトのプロパティを変更してみる。

<!-- app.component.ts -->
export class AppComponent {
  public datas = {
    data1: 1,
    data2: 2
  };
  onClick()
  {
    this.datas.data1 ++;
  }
}

結果

changesが表示されない。

オブジェクトプロパティの変更は検知されない!

stackoverflowで検索

angular - In angular2, how to get onChanges for properties changed on an object sent in for an @Input - Stack Overflow

Q.
How can I detect if there is a change
to any property on settings?

どうやったらオブジェクトプロパティの変更を検知できますか?

A.
Angular will only notice
if the object has been changed to a different object
(i.e., the object reference changed),
so ngOnChanges() can't be used to solve your problem. 
You could implement the ngDoCheck() method in your MyDirective class.

Angularはオブジェクト自体が変更された時(参照先が変わった時)に検知します。 なのでngOnChangesではダメです。 ngDoCheckを実装してください。

ngDoCheckを実装してみる

<!-- child/child.component.ts -->
export class ChildComponent implements OnInit, OnChanges {
  @Input() parentProperty;
  constructor() { } 
  ngOnInit() {
  }
  ngOnChanges() {
    console.log('changes');
  }
  ngDoCheck() {
    console.log('do check');
  }
}

do checkが表示された。

オブジェクトプロパティの変更が検知されている。