Home > Back-end >  Subscribing twice to same observable causing expression changed after checked error
Subscribing twice to same observable causing expression changed after checked error

Time:08-24

I'm trying to subscribe to the same observable twice in my component view:

<ng-container *ngIf="isLoading$ | async">
    Is Loading
</ng-container>

<ng-container *ngIf="!(isLoading$ | async)">
    Is Not Loading
</ng-container>

This is the relevant parts of the .ts file for the same component:

isLoading$: Observable<boolean>;

  ngOnInit() {
        this.isLoading$ = this.loadingService.loading$;
    }

This is the Loading Service:

export class LoadingService {
  
  private loadingSource: ReplaySubject<boolean> = new ReplaySubject<boolean>(1);
  private loadingCount = 0;
  public loading$: Observable<boolean> = this.loadingSource.asObservable();

  private isLoading(): boolean {
    return this.loadingCount > 0;
  }

  public startLoad() {
    this.loadingCount  ;
    this.loadingSource.next(this.isLoading());  
  }

  public endLoad() {
    this.loadingCount--;
    this.loadingSource.next(this.isLoading());
  }
}

And the Loading Interceptor that sets the values in the Loading Service:

export class LoadingInterceptor implements HttpInterceptor {

  constructor(private loadingService: LoadingService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.loadingService.startLoad();
    return next.handle(req)
      .pipe(
        share(),
        finalize(() => {
          this.loadingService.endLoad();
        })
      );
  }
}

The issue I'm having is that when I subscribe to the observable twice using the async pipe as I have done above, I receive the Expression Changed After Checked which reads:

NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.. Find more at https://angular.io/errors/NG0100

Any ideas?

CodePudding user response:

This issue comes because your value is updated before your first value updates your DOM. Please read this article for more info Click here

To fix this issue you can call your endLoad() in ngOnInit() And I think your intercept() #service finalizes() your value and set your Loading to false before ViewInit.

CodePudding user response:

There are two ways to cater this issue:

1. setTimeout():

ngOnInit() {
    setTimeout(() => this.isLoading$ = this.loadingService.loading$, 0);
}

2. Deploy another changeDetection:

constructor(private cd: ChangeDetectorRef) {}

ngOnInit() {
  this.isLoading$ = this.loadingService.loading$;
  this.cd.markForCheck(); //<----add this to make it ready for detection
}

ngAfterViewInit() { // <-----this lifecycle hook is required.
    this.cd.detectChanges();
}
  • Related