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

我将用一个简化的例子来解释我的问题,因为我的代码非常冗长.

我想在isFetching或isDownloading中的任何一个为真时显示某个div.

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

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

当isFetching和isDownloading都为false时,这就是我想要隐藏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;
}

最佳答案 您可能想要使用observable来考虑替代模式,这可以简化您的代码(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的标志.

关于你的代码:

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

我根本不知道它是如何工作的,因为回调函数(函数(快照))内部可能是未定义的,给你一个运行时错误.

我不是Angular内部的专家,但我怀疑发生了什么导致您报告的错误是以下事件序列:

>组件被实例化并且构造函数运行.
> Firebase查询启动.
>调用ngOnInit并检查变化检测变量. isFetching在这一点上仍然是正确的.
> Angular在构建视图方面做了更多工作,你有什么用.
>同时,Firebase查询完成,’isFetching`设置为false.
>在最终完成这一轮渲染之前,Angular会再次检查(它在测试模式下执行此操作),以确保没有任何意外更改.但它有!

如注释中所述,将firebase查询逻辑放在构造函数中会导致整个问题.构造函数应严格限制为基本初始化.它们不应包含业务逻辑,绝对不应包含异步内容.

点赞