ngIf表达式在检查后已更改

4
我将用一个简化的例子来解释我的问题,因为我的代码相当冗长。
isFetching 或者 isDownloading 两个参数之一为true时,我想要显示一个特定的div。
<div *ngIf="(isFetching || isDownloading)">
  My div element is here
</div>

在我的程序开始时,它们都是true,所以应该显示div。在上面的div下面,我有其他元素,这些元素在isFetching更改为false后显示在视图中。(从数据库获取完成后,isFetching被更改为false。)在isFetching更改为false并渲染出元素之后,在这些元素的最后一个元素(是一张图片)下载后,我会将isDownloading更改为false
isFetchingisDownloading都为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;
}

1
这个官方仓库中的这条评论可能会有所帮助。 - Rodrigo Ferreira
1
你可能想把那段代码从构造函数中移出来,放到 ngOnInit 中。 - user184994
@RodrigoFerreira,这确实很有用。由于问题出在我的.html文件结构上,您能否给我提供一些建议,以便我可以重构代码,使其从上到下进行单个更改检测?当isFetchingisDownloading之一为true时,我想显示我的div。由于我无法使用||运算符来完成此操作,我该怎么办?我应该创建另一个元素,它是该div的副本,并仅将*ngIf="isDownloading"附加到它吗?但是,我认为这不是最好的解决方法。 - EDJ
你尝试过@user184994的建议了吗?将它从构造函数移到ngOnInit中? - dAxx_
@user184994,我刚刚尝试了一下。然而,它并没有修复错误。 - EDJ
显示剩余3条评论
1个回答

1
你可以考虑使用可观察对象的替代模式,这可以使你的代码更加简洁(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;
});

我完全不知道这个如何工作,因为回调函数(function(snapshot))中的this可能会是未定义的,从而导致运行时错误。
我不是Angular内部的专家,但我怀疑导致您报告的错误的事件序列如下:
1. 组件被实例化并运行构造函数。 2. Firebase查询启动。 3. 调用ngOnInit并检查变量是否已更改。此时isFetching仍为true。 4. Angular继续构建视图等工作。 5. 与此同时,Firebase查询完成,并将'isFetching`设置为false。 6. 在最终确定渲染之前,Angular再次检查一次(在测试模式下进行此操作),以确保没有意外更改。但是它有!
整个问题都是由于将firebase查询逻辑放在构造函数中引起的,正如评论中所提到的那样。构造函数应严格限制于基本初始化。它们不应包含业务逻辑,绝对不应包含异步内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接