Ingó Vals
Ingó Vals

Reputation: 4898

Angular LoadingService strategy throwing a Expression changed error

I've tried reading up on this and a lot of suggestions to fix this but I'm out of luck. I guess my whole strategy is just bad somehow though I do not realize how.

I have a LoadingService that holds a BehaviourSubject of Boolean. I like to display a loading screen instead of the router-outlet when doing API calls and setting up the view. So I just wanted to set the behavior after that is done which switches from the loading screen to the router outlet.

Here is the service:

export class LoadingService {
  private emitLoading: BehaviorSubject<boolean>;

  constructor() {
    this.emitLoading = new BehaviorSubject<boolean>(true);
  }

  get loading$(): Observable<boolean> {
    return this.emitLoading.asObservable();
  }

  public setLoading(newValue: boolean): void {
    this.emitLoading.next(newValue);
  }
}

And my bootstrapped app component

<div class="container">
    <h1>My App</h1>
    <div *ngIf="loading$ | async">
      <h1>...Loading<h1>
    <div>
    <div [hidden]="loading$ | async">
        <router-outlet></router-outlet>
    </div>
</div>

Where loading$ is exposed from that loading service through the app component

export class AppComponent  {

  constructor(
    private loader: LoadingService
  ) { }

  get loading$(): Observable<boolean> {
    return this.loader.loading$;
  }
}

And I route straight ahead to a component that sets loading to false. I've tried a few different strategies here. ngOnInit(), ngAfterViewInit() , doing the ChangeDetectorRed.detectChanges() but nothing works.

ngAfterViewChecked() {
    this.loader.setLoading(false);
    this.cdRef.detectChanges();
  }

I guess I don't understand the complexity here, or I'm using the Subject wrong. Anyone who can say straight out that this is a bad strategy, or has a way to make it work?

Here is a stackblitz.

Upvotes: 0

Views: 255

Answers (1)

ViqMontana
ViqMontana

Reputation: 5688

As explained in my comment, the reason you are receiving this error is because your app.component.ts is loaded with the variable loading$, but when angular is rendering the child components, loading$ changes, therefore:

the expression has changed after it was checked

What I would recommend is to always show the router-outlet, but instead, display a loading overlay when the routing is navigating.

I have updated your StackBlitz which now displays this overlay when you press submit. This should help in what you are trying to achieve.

Upvotes: 1

Related Questions