请向我解释为什么我一直得到这个错误:ExpressionChangedAfterItHasBeenCheckedError:表达式已经改变后,它被检查。

显然,我只有在开发模式下才会遇到这种情况,在我的产品构建中不会出现这种情况,但这非常烦人,而且我根本不明白在我的开发环境中出现错误而不会在prod上显示的好处——可能是因为我缺乏理解。

通常,修复很简单,我只是把导致错误的代码包装在setTimeout中,就像这样:

setTimeout(()=> {
    this.isLoading = true;
}, 0);

或者使用如下构造函数强制检测更改:

this.isLoading = true;
this.cd.detectChanges();

但是为什么我总是遇到这个错误呢?我想要了解它,这样我就可以在将来避免这些俗套的修复。


当前回答

我得到这个错误,因为我在component.html中使用了一个没有在component.ts中声明的变量。一旦我删除了HTML中的部分,这个错误就消失了。

其他回答

在@ViewChild装饰器中添加static: true

@ViewChild(UploadComponent, { static: true }) uploadViewChild: UploadComponent;

我的问题是我在加载这个对象时打开了一个Ngbmodal弹出框,这个对象在被检查后被改变了。我能够通过打开setTimeout内的模态弹出框来解决它。

setTimeout(() => {
  this.modalReference = this.modalService.open(this.modal, { size: "lg" });
});

一旦我理解了Angular生命周期钩子以及它们与变更检测的关系,我就理解了很多。

我试图让Angular更新一个绑定到元素的*ngIf的全局标志,我试图在另一个组件的ngOnInit()生命周期钩子中更改这个标志。

根据文档,这个方法会在Angular检测到变化之后调用:

在第一个ngOnChanges()之后调用一次。

因此,在ngOnChanges()中更新标志不会启动变更检测。然后,一旦变更检测再次自然触发,标志的值就发生了变化,并抛出错误。

在我的例子中,我修改了这个:

constructor(private globalEventsService: GlobalEventsService) {

}

ngOnInit() {
    this.globalEventsService.showCheckoutHeader = true;
}

:

constructor(private globalEventsService: GlobalEventsService) {
    this.globalEventsService.showCheckoutHeader = true;
}

ngOnInit() {

}

它解决了这个问题:)

当我添加*ngIf时,我的问题很明显,但这不是原因。该错误是由于在{{}}标签中更改模型,然后稍后尝试在*ngIf语句中显示更改后的模型而导致的。这里有一个例子:

<div>{{changeMyModelValue()}}</div> <!--don't do this!  or you could get error: ExpressionChangedAfterItHasBeenCheckedError-->
....
<div *ngIf="true">{{myModel.value}}</div>

为了解决这个问题,我将调用changeMyModelValue()的位置更改为更有意义的位置。

在我的情况下,我希望每当子组件更改数据时调用changeMyModelValue()。这要求我在子组件中创建并发出一个事件,以便父组件可以处理它(通过调用changeMyModelValue())。看到https://angular.io/guide/component-interaction parent-listens-for-child-event

我在RxJS/Observables和静态模拟数据之间有这个问题。首先,我的应用程序使用静态模拟数据,在我的例子中是数据数组

html是这样的:

*ngFor="let x of myArray?.splice(0, 10)"

我们的想法是只显示myArray中的10个元素。Splice()获取原始数组的副本。据我所知,这在Angular中是完全没问题的。

然后我把数据流改为Observable模式,因为我的“真实”数据来自Akita(一个状态管理库)。这意味着我的html变成:

*ngFor="let x of (myArray$ | async)?.splice(0, 10)"

where myArray$是[was]类型的Observable<MyData[]>,这个模板中的数据操作是导致错误发生的原因。不要对RxJS对象这样做。