为什么ngOnChange没有检测到@Input元素更改,而ngOnDetect能够这样做

时间:2016-04-16 23:46:56

标签: javascript typescript angular

考虑这个plunker

注意:要观察在输入链接后重新运行应用程序所需的效果

import {Component, OnInit, Input, OnChanges, DoCheck} from 'angular2/core'

@Component({
  selector: 'sub',
  template: `
    <li  *ngFor="#elem of sub_list">
      <div>{{elem['name']}}</div>
    </li>
    `
})
export class Sub {

  @Input()
  sub_list: Object[];

  ngOnInit(){
    console.log('init');
    console.log(this.sub_list);
  } 

  ngOnChanges(){
    console.log('change');
    console.log(this.sub_list);
  }

  ngDoCheck() {
    console.log('check');
    console.log(this.sub_list);
  }

}
@Component({
  selector: 'my-app',
  template: `
    <div>
      <sub
        [sub_list]="my_list"
      >
      </sub>

    </div>

    `,
  directives: [Sub]
})
export class App {

  my_list: Object[] = [];

  ngOnInit() {
      var vm = this;

    setTimeout(function() {
          for(var i = 0; i < 100; i++) {

        vm.my_list.push({
          'index' : i,
          'name'  : i
        });
      }
    }, 100);

  }
}

如果我尝试在this.sub_list的{​​{1}}中打印Sub,则浏览器会输出一个空列表。

但是我们可以看到ngOnChange仍能正确捕获更改。

这是否有特定原因?

2 个答案:

答案 0 :(得分:4)

在您的情况下,不会在阵列上调用ngOnChanges进行更新。事实上,Angular2会根据引用检测更新。我的意思是如果整个数组的引用没有改变(使用push方法在其中添加元素的情况),则不会调用ngOnChanges方法。

在你的情况下,当调用ngOnChanges时你的数组为null,因为它在设置input元素之前被调用。

在这种情况下,有两种方法可以检测到变化:

  • 使用slice(推送后)或concat等方法更新整个数组引用。

    this.myArray.push({...});
    this.myArray.push = this.myArray.push.slice();
    
  • 利用ngDoCheck方法和IterableDiffers类手动检查更新。该类允许您注册回调,以便在数组中添加(或删除)元素时得到通知。

有关详细信息,请参阅以下链接:

答案 1 :(得分:1)

好的,我已经知道了。使用空数组初始化类字段时会触发ngOnChange,然后在超时回调中更新数组,并且未检测到Thierry正确指向的更改。

Angular包含可以跟踪应用中所有异步事件的zone.js库。 Zone检测到某处执行了超时回调并触发ngDoCheck循环并获得正确的日志。

请参阅plunkr