ngIf 表达式在检查后发生了变化

Posted

技术标签:

【中文标题】ngIf 表达式在检查后发生了变化【英文标题】:ngIf Expression has changed after it was checked 【发布时间】:2019-01-05 21:37:34 【问题描述】:

我将用一个简化的例子来解释我的问题,因为我的代码很长。

isFetchingisDownloading 之一为真时,我想显示某个div。

<div *ngIf="(isFetching || isDownloading)">
  My div element is here
</div>

在我的程序开始时,它们都是真的,所以应该显示 div。在上面的 div 下方,在 isFetching 更改为 false 后,我还有其他元素显示在视图上。 (从数据库提取完成后isFetching 更改为false。)isFetching 更改为false 并渲染元素后,下载这些元素的最后一个元素(它是图像) ,然后我将isDownloading 更改为false

isFetchingisDownloading 都为假时,这是我想隐藏 div 元素的时候。

但是,我刚刚解释的代码给了我这个错误:

Expression has changed after it was checked. Previous value: 'ngIf: true'. Current value: 'ngIf: false'.

我似乎不明白为什么会出现这个问题?我的逻辑有什么问题?如何在不出现此错误的情况下达到预期结果?

编辑:

这段代码在我的类的构造函数中:

firebase.database().ref('/users/' + this.userId).once('value').then(function(snapshot) 
  this.username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  this.isFetching = false;
);

isFetching 更改为false 之后。我的 .html 中还有其他元素会被渲染。然后在加载这些元素的最后一个元素(即图像)后调用此代码(load)="latestElementLoaded()"

latestElementLoaded()
   this.isDownloading = false;

【问题讨论】:

您能否添加负责设置isFetchingisDownloading 的代码? ngIf - Expression has changed after it was checked的可能重复 @user184994,我已经添加了您要求的代码。 This comment 在官方仓库中可能会有所帮助 您可能希望将该代码移出构造函数并移入ngOnInit 【参考方案1】:

您可能需要考虑另一种模式,使用 observables,它可以简化您的代码(AngularFire 值得研究):

this.data$ = this.angularFirestore.doc('some/path').valueChanges();

这会将您的数据作为可观察的(这只是演示代码——检查实际语法)。把它放在ngOnInit,而不是构造函数中。不要乱用.once 或快照或其他样板。

现在,在你的模板中,你可以写

<div *ngIf="data$ | async as data; else notFetched">
  Data is data | json
  <ng-template #notFetched>Data is not fetched yet..wait...</ng-template>
</div>

这完全消除了对isFetching-like 标志的需要。

关于你的代码:

firebase.database().ref('/users/' + this.userId).once('value').then(function(snapshot) 
  this.username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  this.isFetching = false;
);

我根本不知道这将如何工作,因为回调函数 (function(snapshot)) 中的 this 可能是未定义的,给你一个运行时错误。

我不是 Angular 内部的专家,但我怀疑导致您报告的错误的原因是以下事件序列:

    组件被实例化,构造函数运行。 Firebase 查询开始。 调用ngOnInit 并检查检测到变化的变量。 isFetching 在这一点上仍然成立。 Angular 做更多的工作来构建视图和你有什么。 与此同时,Firebase 查询完成,并且“isFetching”设置为 false。 在完成这一轮渲染之前,Angular 会再检查一次(它在测试模式下执行此操作),以确保没有任何意外更改。但它有!

正如评论中提到的,这整个问题是由将 firebase 查询逻辑放在构造函数中引起的。构造函数应严格限于基本初始化。它们不应该包含业务逻辑,并且绝对不应该包含异步的东西。

【讨论】:

以上是关于ngIf 表达式在检查后发生了变化的主要内容,如果未能解决你的问题,请参考以下文章

例外:在检查离子输入后,表达式发生了变化

表达式___在检查后发生了变化

检查后表达式发生了变化 - 角度

使用反应式表单在 Angular 中检查后,表达式发生了变化

Angular 2 / PrimeNG - 表达式在检查后发生了变化。在最后一个无效的表单控件上绑定 NgModel

在我的表格组件中检查后,表达式发生了变化