I'm facing some common issue on Angular template, I have this general template for all my pages and inside of it I have a *ngIf with a spinner inside and another one with my router-outlet.
The interceptor controlls the behavior and visibility of the spinner, so with that comes the error, in a specific component I subscribe on a http method on a ngOnInit and the result of that is the error.
This error just happen if I call some method on lifecycle methods. I already tried some workarounds like envolve the setSpinnerState with setTimeout and tried to use other lifecycle hooks(AfterViewInit, AfterContentInit...).
The interceptor
export class InterceptorService implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): import('rxjs').Observable<HttpEvent<any>> {
this.layoutService.setSpinnerState(true);
return next.handle(this.handlerRequest(req)).pipe(
delay(3000),
finalize(() => {
this.layoutService.setSpinnerState(false);
})
);
}
constructor(private authService: AuthService, private layoutService: LayoutService) { }
private handlerRequest(req: HttpRequest<any>) {
let request;
if (this.authService.isLoggedIn() && !req.url.includes('/assets/i18n/')) {
request = req.clone({
url: environment.api.invokeUrl + req.url,
headers: req.headers.append('Authorization', 'Bearer ' + this.authService.getAcessToken())
});
} else if (req.url.includes('/assets/i18n/')) {
request = req.clone();
} else {
request = req.clone({
url: environment.api.invokeUrl + req.url
});
}
return request;
}
}
Layout Service:
export class LayoutService {
private isSpinner: boolean = true;
constructor() { }
public setSpinnerState(state: boolean): void {
this.isSpinner = state;
}
public getSpinnerState():boolean{
return this.isSpinner;
}
}
The general template(LayoutComponent)
<div class="page-wrapper fixed-nav-layout">
<app-header (toggleEvent)="receiveToggle($event)"></app-header>
<!--Page Body Start-->
<div class="container-fluid">
<div class="page-body-wrapper sidebar-icon" [class.sidebar-close]="toggle">
<app-sidebar class="page-sidebar page-sidebar-open"></app-sidebar>
<div class="page-body p-t-10">
<app-breadcrumb></app-breadcrumb>
<router-outlet *ngIf="!layoutService.getSpinnerState()"></router-outlet>
<div class="loader-box d-flex justify-content-center align-self-center" *ngIf="layoutService.getSpinnerState()" async>
<div class="loader">
<div class="line bg-default"></div>
<div class="line bg-default"></div>
<div class="line bg-default"></div>
<div class="line bg-default"></div>
</div>
</div>
</div>
</div>
<!--Page Body End-->
</div>
The component with the subscribe method
export class EditProfileComponent implements OnInit {
public userProfile = new UserProfile();
constructor(private userService: UserService) {
}
ngOnInit() {
this.getUser();
}
public getUser() {
// debugger
this.userService.getUser().subscribe(data => {
this.userProfile = Amazon.feedUser(data);
}, err => {
return new ErrorHandler().show(err.message);
});
}
}
And the error stack
ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: true'. Current value: 'ngIf: false'.
at viewDebugError (core.js:28792)
at expressionChangedAfterItHasBeenCheckedError (core.js:28769)
at checkBindingNoChanges (core.js:29757)
at checkNoChangesNodeInline (core.js:44442)
at checkNoChangesNode (core.js:44415)
at debugCheckNoChangesNode (core.js:45376)
at debugCheckDirectivesFn (core.js:45273)
at Object.eval [as updateDirectives] (LayoutsComponent.html:10)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:45258)
at checkNoChangesView (core.js:44248)
At last I tried ChangeDetectorRef on LayoutComponent, but error doesn't changed.
export class LayoutsComponent implements OnChanges {
public toggle;
openToggle: boolean;
constructor(public navService: NavService, public layoutService: LayoutService, private cd: ChangeDetectorRef) {
if (this.navService.openToggle === true) {
this.openToggle = !this.openToggle;
this.toggle = this.openToggle;
}
}
ngOnChanges(): void {
this.cd.detectChanges();
}
receiveToggle($event) {
this.openToggle = $event;
this.toggle = this.openToggle;
}
}
The error reproduced on stackblitz: https://stackblitz.com/edit/angular-xyulo9