我已阅读有关此错误的文档,并且我想我理解出现此问题的原因。我在尝试找出适合我的替代架构时遇到问题。
我网站的根组件(app.component)上有一个“正在加载”组件。它是一个第三方组件(ngx-loading),基本上会抛出一个加载指示器,向用户表明应用程序中正在发生一些需要一些时间的事情。加载组件接受一个参数来告诉它是否显示:
<ngx-loading [show]="loading" [config]="{ backdropBorderRadius: '14px' }"></ngx-loading>
我有一个站点服务来保存此数据,我的应用程序在 OnInit 中获取服务数据:
this.siteService.getLoading().takeUntil(this.ngUnsubscribe).subscribe(res => {this.loading = res})
这一切的伟大之处在于,我可以从应用程序中的任何位置更改站点服务值,并控制是否弹出此加载指示器。糟糕的是,现在我看到了这个 ExpressionChangedAfterItHasBeenCheckedError 错误。
再次,我想我明白为什么会发生错误,但是到目前为止我看到的解决方案不允许我继续使用这个简单的组件来处理我所有的“加载”调用。或者我错过了什么?
站点服务:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class SiteService {
private currentRoute = new Subject<string>();
private currentAction = new Subject<string>();
private loading = new BehaviorSubject<boolean>(false);
constructor() {
}
public menuState:string = 'in';
toggleMenuPicker() {
this.menuState = this.menuState === 'out' ? 'in' : 'out';
}
getCurrentRoute(): Observable<string> {
return this.currentRoute.asObservable();
}
setCurrentRoute(route: string) {
this.currentRoute.next(route);
}
getCurrentAction(): Observable<string> {
return this.currentAction.asObservable();
}
setCurrentAction(action: string) {
this.currentAction.next(action);
}
getLoading(): Observable<boolean> {
return this.loading.asObservable();
}
setLoading(show: boolean) {
this.loading.next(show);
}
}
应用程序组件
import { Component, OnDestroy, AfterContentInit } from '@angular/core';
import { trigger, state, style, transition, animate} from '@angular/animations';
import { SiteService } from './site/site.service';
import 'rxjs/add/operator/takeUntil';
import { Subject } from 'rxjs/Subject';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
animations: [
trigger('menuState', [
state('in', style({
transform: 'translate3d(-100%, 0, 0)'
})),
state('out', style({
transform: 'translate3d(0, 0, 0)'
})),
transition('in => out', animate('200ms ease-in-out')),
transition('out => in', animate('200ms ease-in-out'))
])
]
})
export class AppComponent implements OnDestroy, AfterContentInit {
private ngUnsubscribe: Subject<void> = new Subject<void>();
public loading;
constructor(public siteService: SiteService) {
}
ngAfterContentInit() {
this.siteService.getLoading().takeUntil(this.ngUnsubscribe).subscribe(res => {this.loading = res})
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
}
最佳答案
您可以使用 ChangeDetectionStrategy.OnPush 或 ChangeDetectorRef.detach() 来保留单个组件,同时避免错误。
这是一种可能的解决方案:
@Component({
selector: 'loader',
template: `<ngx-loading [show]="loading"></ngx-loading>`
})
export class LoaderComponent {
public loading;
constructor(public siteService: SiteService, private changeDetectorRef: ChangeDetectorRef) {
this.changeDetectorRef.detach();
this.siteService.getLoading()
.takeUntil(this.ngUnsubscribe)
.subscribe(res => {
this.loading = res;
this.changeDetectorRef.detectChanges();
});
}
}
您可以创建此组件并在 AppComponent 模板中使用它。
关于Angular2 ExpressionChangedAfterItHasBeenCheckedError 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46837438/