为啥 ngOnChange 没有检测到 @Input 元素更改而 ngOnDetect 能够这样做
Posted
技术标签:
【中文标题】为啥 ngOnChange 没有检测到 @Input 元素更改而 ngOnDetect 能够这样做【英文标题】:Why is ngOnChange not detecting @Input element change whil ngOnDetect was able to do so为什么 ngOnChange 没有检测到 @Input 元素更改而 ngOnDetect 能够这样做 【发布时间】:2016-08-08 20:11:09 【问题描述】:考虑一下plunker
注意:进入链接后需要重新运行app才能观察效果
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);
如果我尝试在Sub
的ngOnChange
中打印出this.sub_list
,浏览器会输出一个空列表。
但是我们可以看到ngDoCheck
仍然正确地捕获了更改。
这有什么具体原因吗?
【问题讨论】:
【参考方案1】:好的,我知道了。 ngOnChanges
在您使用空数组初始化类字段时触发,然后您在超时回调中更新数组,并且由于 Thierry 正确指出的更改未被检测到。
Angular 包含 zone.js 库,可以跟踪应用程序中的所有异步事件。 Zone 检测到超时回调在某处执行并触发ngDoCheck
循环,您将获得正确的日志。
见plunkr
【讨论】:
如果你注释掉DoCheck
,result 是一样的。我希望OnChanges
能够捕捉到模型变化【参考方案2】:
在您的情况下,不会调用 ngOnChanges 来更新阵列。事实上,Angular2 根据引用检测更新。我的意思是如果整个数组的引用没有改变(使用 push 方法在其中添加元素时就是这种情况),则不会调用 ngOnChanges 方法。
在您的情况下,当调用 ngOnChanges 时,您的数组为 null,因为它是在设置输入元素之前调用的。
在这种情况下有两种检测变化的方法:
使用 slice(推送后)或 concat 等方法更新整个数组引用。
this.myArray.push(...);
this.myArray.push = this.myArray.push.slice();
利用 ngDoCheck 方法和 IterableDiffers 类来手动检查更新。该类允许您注册回调,以便在数组中添加(或删除)元素时收到通知。
查看这些链接了解更多详情:
Angular2 change detection: ngOnChanges not firing for nested object https://angular.io/docs/ts/latest/api/core/DoCheck-interface.html【讨论】:
嗯,这很令人困惑,如果Angular2
总是检查引用相等,那么changeDetection: ChangeDetectionStrategy.OnPush
的意义何在
OnPush 是一种告诉 angular2 不要检查特定组件子树的方法。例如对于不可变对象很有用。在所有情况下,“更改”默认对应于一个新实例。利用 ngDoCheck 是一种提供自定义方式的方式。
查看此链接了解更多详情:blog.thoughtram.io/angular/2016/02/22/….以上是关于为啥 ngOnChange 没有检测到 @Input 元素更改而 ngOnDetect 能够这样做的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Angular 2 ngOnChanges 不响应输入数组推送
Angular ngOnChanges 和变化检测策略似乎是矛盾的?
IONIC2/Angular2 ngOnChange 不起作用