angular - 面对“ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked”来显示/隐藏加载器
问题描述
我在父组件(AppComponent)中有一个通用加载器以及router-outlet
(加载子组件)。在子组件中,我们更改值以分别在调用 API 之前和之后显示和隐藏加载器。因此发生此错误。
例如这是我的装载机app.cpmponent.html
:
<p [ngClass]="(overlappingProgress | async) ? 'display-block' : 'display-none'">holaaaaaaaaaaaaaaa</p>
这overlappingProgress
是一种observable
通过async
管道解析的变量。
在子组件中,我有一个需要来自服务器的一些数据的表单。因此,在ngOnInit
子组件内部,我ngrx
按以下顺序调度了一些操作(正如我们正在使用的那样) -
- showOverlappingProgress() // 它使 reducer 中的加载属性为 true
- 获取数据()
- hideOverlappingProgress() // 它使 reducer 中的加载属性为 false
因此,app.component.ts
为了检测该更改,我会听取更改以更新显示/隐藏加载程序。
this.overlappingProgress = this.store.select(s => s.app.overlappingProgress);
我有一些想法,它将先前/旧值与第一个摘要周期的值进行比较,但该值在摘要周期内发生变化,因此,当它运行第二个摘要周期时,值不匹配,因此发生此错误。
我在stackblitz中使用更简单的版本来模拟这种情况。
我找到了一些建议使用的解决方案setTimeout()
or this.cdr.detectChanges()
。
个人觉得不太setTimeout()
行。此外,手动触发detectchanges
可能会做很多额外的工作,因为所有子组件都在起诉这个加载器,每次它都会触发和额外的变化检测。
因此,我在这里就在这种情况下应该是最佳解决方案获得一些建议。
解决方案
它有父子关系。子组件更改在父组件的表达式中使用的父组件的值。
为了解决这个问题,我稍微改变了父子结构。我创建了一个名为的新模块
FfLoadingIndicatorComponentModule
,它有一个名为FfLoadingIndicatorComponent
. 在该组件中,我订阅了它显示的更改,分别隐藏了加载器。最后,我将该模块导入AppModule
以使用来自应用程序组件的新创建的加载指示器组件。
这里主要是单独的组件及其与应用程序组件的关系。让我们看看代码。代码示例:
ff-loading-indicator.component.ts
@Component({
selector: 'ff-loading-indicator',
templateUrl: './ff-loading-indicator.component.html',
styleUrls: ['./ff-loading-indicator.component.scss']
})
export class FfLoadingIndicatorComponent implements OnInit {
progress$: Observable<boolean>;
overlappingProgress$: Observable<boolean>;
constructor(private store: Store<State>) { }
ngOnInit(): void {
this.progress$ = this.store.select(s => s.app.progress);
this.overlappingProgress$ = this.store.select(s => s.app.overlappingProgress);
}
}
ff-loading-indicator.component.html
<div [ngClass]="(progress$ | async) ? 'display-block' : 'display-none'">
<mat-progress-bar class="ff-z-index-above-toolbar ff-general-loading-indicator" mode="indeterminate" color="accent"></mat-progress-bar>
</div>
最后在app.component.html
.
app.component.html
<ff-loading-indicator></ff-loading-indicator>
您可以在stackblitz中找到更改。
注意:
FfLoadingIndicatorComponent
可以直接导入AppModule
. 由于我更喜欢模块方法,因此我创建了一个单独的模块并将其导入AppModule
推荐阅读
- coldfusion - 带有 base64 图像的 v-card-media
- ruby-on-rails - 在 Mongoid 中按多个字段和条件排序集合
- django - 线程中未处理的异常由
- java - JAVA 安装在 Mac 上但无法正常工作
- python - 主线程加载tensorflow模型,用于子线程报错
- r - 仅选择存在最后日期的行
- python - global_variables_initializer() 初始化哪些变量?
- ruby-on-rails - Ruby on Rails 通过关联的集合代理进行交互并更新属性
- c++ - 将指针强制转换为 lldb 中的类型
- django - apache2(mod_wsgi-express):语法错误