当投影组件在祖先组件中设置值时,我收到“检查后更改”错误。以下是我的问题的复制品:plnkr.co/edit/jJNFsJdf1KDSF3Fqhfb8
@Component({
selector: 'app-component',
template: `
<test-component>
<ng-template #tpl>
<projected-component [rootComponent]="this"></projected-component>
</ng-template>
</test-component>
{{change}}
`
})
export class AppComponent {
change = 0;
}
@Component({
selector: 'test-component',
template: `
<ng-template [ngTemplateOutlet]="tplRef"></ng-template>
`
})
export class TestComponent {
@ContentChild('tpl') tplRef: TemplateRef<any>;
}
@Component({
selector: 'projected-component',
template: `
<div>{{parent}}</div>
`
})
export class ProjectedComponent {
@Input() rootComponent: TestApp;
ngOnInit() {
this.rootComponent.change++;
}
}
错误是:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'null: 0'. Current value: 'null: 1'.
我首先是由Matt Brophy的nested form pattern来解决这个问题。这是一个美丽的模式,但我认为他可能忽略了这个问题,或者它在早期版本的Angular中不是问题。我原来的问题是here。由于我没有简化的实时复制,因此我没有成功获得解决方案的帮助。
如何在不出错的情况下进行设置?
答案 0 :(得分:2)
问题是您是在同一个更改检测周期中更改父级的数据。您可以通过简单地将更改包装在setTimeout()
调用中来阻止该错误被抛出,以确保它在更改检测周期完成后运行。
ngOnInit() {
console.log(this.rootComponent);
setTimeout(() => this.rootComponent.change++);
}
您通常不会遇到这些问题,因为它通常是一些触发数据更改的用户事件,而不是在更改检测生命周期中运行的某些方法(至少不会更改父数据)。
话虽如此,但通常不应修改由另一个组件拥有的数据。正如@Harry Ninh所提到的,最好广播一个事件来通知父母需要更新数据(在这种情况下,你仍然需要用setTimeout()
包装,因为你仍然会广播在同一个更改检测周期中更改父级数据的事件。)