Ionic 5 + Angular LoadingController with Http Interceptor Loader Present and Dismiss issue

Ionic 5 LoadingController Not working with Http Interceptor

This issue happen when i’m calling multiple http requests at same time in ngOnInit() method.

I have tried 2 different approaches

Approach 1:

public async loaderPresent(): Promise<void> {

    if (!this.isShowing) {
      this.isShowing = true;
      this.loading = await this.loadingController.create({
        cssClass: "my-custom-loader-class",
        message: "Please wait ...",
        backdropDismiss: true
      });
      return await this.loading.present();
    } else {
      this.isShowing = true;
    }
  }
public async loaderDismiss(): Promise<void> {

   // console.log('Loading dismissed ');

    if (this.loading && this.isShowing) {
      this.isShowing = false;
      await this.loadingController.dismiss();
    }
  }

In this case loder still present even all requests completed.

Note: Loader Not Dismissed when multiple http requests called in ngOnInit( ) method

Approach 2

In This Approach we are using Subject rxjs Operator

import { Subject } from ‘rxjs’;

private loadingRequestsStream$: Subject;

private initValues() {
    this.loaderElement = null;
    this.lazyDismissTimer = null;
    this.loadingRequestsStream$ = new Subject();
    this.loadingRequestsStream$.pipe(
      distinctUntilChanged(),
      concatMap(loader => {
        if (loader) {
          return this.createLoader()
        } else {
          return this.dismissLoader()
        };
      })
    )
      .subscribe(); // we do not worry of unsubscribing here since this service will always be used across the app
  };
private async createLoader(): Promise<void> {
    // we check if there is a loader already instantiated:
    if (!this.loaderElement) {
      // if not we create new loader and limit its max duration to 2000ms to prevent blocking loader to hangout indefinitely
      this.loaderElement = await this.loadingController.create({
        cssClass: "my-custom-loader-class",
        message: "Please wait ...",
        //duration: 3000
      });
      // its essential we return a Promise here as this is what concatMap will leverage for serialization
      return this.loaderElement.present();
    } else {
      // if loader element exists already we just return resolved promise:
      return Promise.resolve();
    };
  };
private async dismissLoader(): Promise<void> {
    // here we check if loader element exists and that there is no timer running already
    if (this.loaderElement && !this.lazyDismissTimer) {
      // we set the timer
      this.lazyDismissTimer = setTimeout(async () => {
        // after 700ms we dismiss our loader element:
        await this.loaderElement.dismiss();
        // nullify our properties right after dismiss promise fulfilled itself:
        this.loaderElement = null;
        clearTimeout(this.lazyDismissTimer);
        this.lazyDismissTimer = null;
        // still remember to return a promise to let concatMap know it can proceed
        return Promise.resolve();
      }, 700)
    } else {
      // if loader element does not exist or if there is already a timer running - there is nothing to dismiss, we just return empty promise
      return Promise.resolve();
    };
  };
public showLoader() {
    this.loadingRequestsStream$.next(true);
  };

  public hideLoader() {
    this.loadingRequestsStream$.next(false);
  };

In this case Loader Dismissing before All Requests completed.

Note: Loader Not Dismissed when multiple http requests called in ngOnInit( ) method

in your Approach 1:

this is wrong. you need to dismiss the presented loader.

replace this.loadingController.dismiss(); with this.loading.dismiss();

is this works ?

No Brother Still it’s not working,
Before all requests complete it’s dismissing

You mean, after first api request the loader gets dismissed before the second api call right?

Yes , i have a situation like in ngOnInit() method have to make 4 to 5 http calls, if 1st one completed then after immediately loader gets dismissed before complete remaining requests

Ok understood.
Please store the loaders in different properties, then after in your api subscription dismiss that loader.
i’m giving sample code below:

private loading: any;
public async loaderPresent(): Promise<any> {

      const loading = await this.loadingController.create({
        cssClass: "my-custom-loader-class",
        message: "Please wait ...",
        backdropDismiss: true
      });

      await loading.present();

     return loading;
  }
async getData() {
  this.loading = await this.loaderPresent();
  this.http.get('url here').subscribe(
  res => {
  if (this.loading) {
     this.loading.dismiss();
   }
}
)
}

// in this way you can re-use the loading controller.

// i think this will resolve your issue!

Hi Bro thank you for your Solution Update , But I want to use this approach in Interceptor

 constructor(private route: ActivatedRoute, public loaderService: LoaderService) { }
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.loaderService.show();
        return next
            .handle(request)
            .pipe(finalize(() => this.loaderService.hide())
            )

    }

like this

i didn’t do like this before.

i’m posting the code below please check once if that works or not.

as i mentioned above, create a loader like that then try the below approach in interceptor,

private loaderControllers = [];

 constructor(private route: ActivatedRoute, public loaderService: LoaderService) { }
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
       
       const loader = this.loaderService.show();
       this.loaderControllers.push(loader);
    
       return next
            .handle(request)
            .pipe(finalize(() => 
                if (this.loaderControllers.length > 0) {
                   this.loaderControllers[0].dismiss();
               }
              )
            )

    }

Try this approach. let me know if that works or not .

I tried this one also but not working it’s behaviour seems like my 2nd approach… If you seen my approach 2 then check that one. it’s happening like dismissing before completing all the requests

find the sample code git repo

@mhartington
Ionic 5 LoadingController Not working with Http Interceptor

This issue happen when i’m calling multiple http requests at same time in ngOnInit() method.

I have tried below Approach

Approach :

In This Approach we are using Subject rxjs Operator

import { Subject } from ‘rxjs’;

private loadingRequestsStream$: Subject;

private initValues() {
    this.loaderElement = null;
    this.lazyDismissTimer = null;
    this.loadingRequestsStream$ = new Subject();
    this.loadingRequestsStream$.pipe(
      distinctUntilChanged(),
      concatMap(loader => {
        if (loader) {
          return this.createLoader()
        } else {
          return this.dismissLoader()
        };
      })
    )
      .subscribe(); // we do not worry of unsubscribing here since this service will always be used across the app
  };
private async createLoader(): Promise<void> {
    // we check if there is a loader already instantiated:
    if (!this.loaderElement) {
      // if not we create new loader and limit its max duration to 2000ms to prevent blocking loader to hangout indefinitely
      this.loaderElement = await this.loadingController.create({
        cssClass: "my-custom-loader-class",
        message: "Please wait ...",
        //duration: 3000
      });
      // its essential we return a Promise here as this is what concatMap will leverage for serialization
      return this.loaderElement.present();
    } else {
      // if loader element exists already we just return resolved promise:
      return Promise.resolve();
    };
  };
private async dismissLoader(): Promise<void> {
    // here we check if loader element exists and that there is no timer running already
    if (this.loaderElement && !this.lazyDismissTimer) {
      // we set the timer
      this.lazyDismissTimer = setTimeout(async () => {
        // after 700ms we dismiss our loader element:
        await this.loaderElement.dismiss();
        // nullify our properties right after dismiss promise fulfilled itself:
        this.loaderElement = null;
        clearTimeout(this.lazyDismissTimer);
        this.lazyDismissTimer = null;
        // still remember to return a promise to let concatMap know it can proceed
        return Promise.resolve();
      }, 700)
    } else {
      // if loader element does not exist or if there is already a timer running - there is nothing to dismiss, we just return empty promise
      return Promise.resolve();
    };
  };
public showLoader() {
    this.loadingRequestsStream$.next(true);
  };

public hideLoader() {
    this.loadingRequestsStream$.next(false);
  };

In this case Loader Dismissing before All Requests completed.

Note: Loader Not Dismissed when multiple http requests called in ngOnInit( ) method

Please Help on Resolving this issue

For reproducing issue please find the below mentioned repo
https://github.com/Madhukumar1226/ionic-Issues.git