为什么这个组件在这个简单的砰砰声中
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App {
message:string = 'loading :(';
ngAfterViewInit() {
this.updateMessage();
}
updateMessage(){
this.message = 'all done loading :)'
}
}
扔:
例外:表达式'I'm {{message}} in App@0:5'在被检查后发生了变化。之前的值:'I'm loading:('。当前值:'I'm all done loading:)' in [I'm {{message}} in App@0:5]
当我所做的一切都是更新一个简单的绑定时,我的视图被启动?
正如drewmoore所说,在这种情况下,正确的解决方案是手动触发当前组件的变更检测。这是使用ChangeDetectorRef对象(从angular2/core导入)的detectChanges()方法完成的,或者它的markForCheck()方法,该方法也会更新任何父组件。相关例子:
import { Component, ChangeDetectorRef, AfterViewInit } from 'angular2/core'
@Component({
selector: 'my-app',
template: `<div>I'm {{message}} </div>`,
})
export class App implements AfterViewInit {
message: string = 'loading :(';
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewInit() {
this.message = 'all done loading :)'
this.cdr.detectChanges();
}
}
这里还有Plunkers演示了ngOnInit, setTimeout和enableProdMode方法以防万一。
关于ExpressionChangedAfterItHasBeenCheckedError错误的一切你需要知道的文章详细解释了这种行为。
你设置的问题是ngAfterViewInit生命周期钩子是在变更检测处理DOM更新后执行的。你在这个钩子中有效地改变了模板中使用的属性,这意味着DOM需要重新渲染:
ngAfterViewInit() {
this.message = 'all done loading :)'; // needs to be rendered the DOM
}
这将需要另一个变更检测周期,而Angular在设计上只运行一个摘要周期。
你基本上有两种解决方法:
使用setTimeout, Promise异步更新属性。然后在模板中引用异步可观察对象
在DOM更新之前执行钩子中的属性更新- ngOnInit, ngDoCheck, ngAfterContentInit, ngAfterContentChecked。
在我的例子中,它发生在p-radioButton上。问题是,我使用的名称属性(这是不需要的)旁边的formControlName属性,就像这样:
<p-radioButton formControlName="isApplicant" name="isapplicant" value="T" label="Yes"></p-radioButton>
<p-radioButton formControlName="isApplicant" name="isapplicant" value="T" label="No"></p-radioButton>
我还将初始值“T”绑定到is申请人窗体控件,如下所示:
isApplicant: ["T"]
我通过删除单选按钮中的name属性来解决这个问题。
此外,因为2个单选按钮具有相同的值(T),这在我的情况下是错误的,简单地将其中一个值更改为另一个值(例如F)也解决了这个问题。