我将用一个简化的例子来解释我的问题,因为我的代码非常冗长.
我想在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查询逻辑放在构造函数中会导致整个问题.构造函数应严格限制为基本初始化.它们不应包含业务逻辑,绝对不应包含异步内容.