Raventus
Raventus

Reputation: 71

ngIF of Angular to display loader didn't work correctly

I'm very confused about one problem. I need to display the loader spinner while my app is getting answers from an async function. To solve this task I paste the loader component from my app.component like this:

<div class="sticky-top">  
  <app-menu></app-menu>
</div>

<div>
  <router-outlet></router-outlet>
</div> 

<!-- Loader-->
<div *ngIf=" isShowIndicator" class="position">
  <app-loader > </app-loader> 
</div>

if the isShowIndicator (boolean) is true - the loader is displayed correctly if it false - the loader is disappeared.

But I need to change the value of this variable, so I try to do three attempts in my app.component.ts file, and all of this attempts is change the value of isShowIndicator, but my loader didn't appear. Can you explain me, why this is happened? Thank you.

The code of app.component.ts is :

import { Component, ChangeDetectorRef } from '@angular/core';
import { LoaderService } from './services/additional/loader';
import { Router, RouterModule, NavigationStart, NavigationEnd, RouterEvent, Event } from '@angular/router';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  isShowIndicator: boolean = true;

  constructor(private _router: Router, private loader: LoaderService, public cd: ChangeDetectorRef) {
// first attempt - use the Observable from my loader service: 
    this.GetLoadingState().subscribe(element => {
      console.log("Show Indicator Obsrvable " + `${element}`);
      this.isShowIndicator = element;
      console.log("Show Indicator Obsrvable " + this.isShowIndicator);
    })
// second attempt - use router events to change the value of isShowIndicator
    this._router.events.subscribe((routerEvent: Event) => {
      if (routerEvent instanceof NavigationStart) {

        this.isShowIndicator = true;
        console.log("true from route " + this.isShowIndicator);
      }

      else if (routerEvent instanceof NavigationEnd) {
        console.log("false from route " + this.isShowIndicator);
        this.isShowIndicator = false;
      }
    });
// third attempt is use the behavior subject object 
    this.loader.ShowIndicator.subscribe(element => {
      console.log("Show Indicator " + `${element}`);
      this.isShowIndicator = element;
      console.log("Show Indicator " + this.isShowIndicator);
    });
  }

  GetLoadingState(): Observable<boolean> {

    return this.loader.ShowIndicator.asObservable();

  }
}

The loader service is implement like this:

import { Injectable } from '@angular/core';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';

@Injectable({
  providedIn: 'root'
})
export class LoaderService {

    public ShowIndicator: BehaviorSubject<boolean> =
    new BehaviorSubject<boolean>(true);

    display (value: boolean) {
        this.ShowIndicator.next(value);
    }
}

in my code I gave the new value to loader service like this:

 constructor(private loader: LoaderService) {
    this.loader.display(true);
    //some async code
    this.loader.display(false); // inside the subscribe method of course
  }

Upvotes: 1

Views: 829

Answers (1)

Derviş Kayımbaşıoğlu
Derviş Kayımbaşıoğlu

Reputation: 30565

It may be better If you solve this by HttpInterceptors.

Something like this:

@Injectable({
  providedIn: 'root'
})
export class LoaderInterceptorService implements HttpInterceptor {
  constructor(private loaderService: LoaderService) { }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.showLoader();
    return next.handle(req).pipe(tap((event: HttpEvent<any>) => { 
      if (event instanceof HttpResponse) {
        this.onEnd();
      }
    },
      (err: any) => {
        this.onEnd();
    }));
  }
  private onEnd(): void {
    this.hideLoader();
  }
  private showLoader(): void {
    this.loaderService.show();
  }
  private hideLoader(): void {
    this.loaderService.hide();
  }
}

Reference

Edit

In your code

 constructor(private loader: LoaderService) {
    this.loader.display(true);
    //some async code
    this.loader.display(false); // inside the subscribe method of course
  }

what you need to do is

constructor(private loader: LoaderService) {
    this.loader.display(true);
    this.subscription = this.dataSvc.data.subscribe(
        data => console.log('Data:', data),
        err => console.log(err),
        () => this.loader.display(false)
    );
}

Upvotes: 1

Related Questions