我有一个看起来像这样的子组件:
@Component({
selector: 'app-child',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
{{text}}
`
})
export class ChildComponent {
@Input() text = '';
constructor(public host: ElementRef) { }
}
一个看起来像这样的父组件:
@Component({
selector: 'app-parent',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<ng-content></ng-content>`
})
export class ParentComponent {
@ContentChild(ChildComponent) child: ChildComponent;
constructor(private cdr: ChangeDetectorRef) { }
ngAfterContentInit() {
this.child.text = 'hello';
this.child.host.nativeElement.addEventListener('click', () => {
this.child.text = 'from click';
this.cdr.detectChanges();
});
}
第一次分配给text
属性工作正常,但是当我单击按钮并尝试再次更改text
属性时,没有任何事情发生。
由于我的了解,这令人困惑:
1. click事件应触发更改检测,text属性不同,因此应该更新。
2.我明确地打电话给detectChanges()
,这也应该从我所知道的那里检查孩子们。
我错过了什么?
答案 0 :(得分:4)
问题与GitHub上报告的this issue有关。它发生在:
OnPush
更改检测策略用于子组件AngularInDepth.com给出的解释:
编译器没有办法生成检查所需的信息 绑定因为它无法在模板中找到这些绑定。 OnPush与输入绑定紧密绑定。重要的是什么 Angular检查绑定的第二部分(prop中的prop) 例子如下),而不是第一个(i):
<child [i]="prop">
确定是否应该为孩子运行更改检测 零件。在检查父组件时它会这样做。如果你不这样做 向编译器显示应该使用哪个父属性来更新子级 输入绑定,它不能生成必要的信息时使用 检查父母。因此检查子组件上的@Input是不是 足够。这是变化检测的机制,我什么都看不到 它可以改变的方式。
yurzui在讨论中建议的一种解决方法是在设置ChangeDetectorRef.markForCheck
属性后调用子组件中的text
,如this stackblitz所示。事实上,它可以在不调用父组件中的ChangeDetectorRef.detectChanges
的情况下工作。
export class ChildComponent {
private _text = '';
@Input()
get text() {
return this._text;
}
set text(val) {
if (this._text !== val) {
this.cdRef.markForCheck();
}
this._text = val;
}
constructor(public host: ElementRef, private cdRef: ChangeDetectorRef) { }
}