pratik jaiswal
pratik jaiswal

Reputation: 2075

Ionic 4 loading interceptor can't dismiss loading

I am trying to create an Http interceptor to display loading in all the pages. But I am not able to dismiss the loading controller

I have followed this https://www.youtube.com/watch?v=IJWCpa_-MeU But the problem is loading is displayed infinitely.

Actually I am a bit new to these concepts. So please help me out.

Thank you very much

I have edited my code. Please find an image of console.log value. There is a problem if you are making multiple Http request on the same page. It is creating loader even if old one exists.

 @Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {
  constructor(
    private loadingCtrl: LoadingController,
    private toastCtrl: ToastController,
    private alertCtrl: AlertController,
  //  private fakeHttp: FakeHttpService
  ) {}

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    this.loadingCtrl.getTop().then(hasLoading => {
      if (!hasLoading) {

        console.log("loading")

        this.loadingCtrl.create({
          spinner: 'circular',
          translucent: true
        }).then(loading => loading.present());
      }
    });

    return next.handle(request).pipe(
      catchError(err => {
        if (err instanceof HttpErrorResponse) {
          switch ((<HttpErrorResponse>err).status) {
            case 401:
           //   return this.handle401Error(request, next);
           // handle 401 here
           console.log("401")
            default:
              return throwError(err);
          }
        } else {
          return throwError(err);
        }
      }),
      retryWhen(err => {
        let retries = 1;
        return err.pipe(
          delay(1000),
          tap(() => {
            // this.showRetryToast(retries);
          }),
          map(error => {
            if (retries++ === 3) {
              throw error; // Now retryWhen completes
            }
            return error;
          })
        );
      }),
      catchError(err => {
      //  this.presentFailedAlert(err.error['msg']);
        return EMPTY;
      }),
      finalize(() => {
        console.log("hii")
        this.loadingCtrl.getTop().then(hasLoading => {
          if (hasLoading) {
            this.loadingCtrl.dismiss();
          }
        });
      })
    );
  }

Here is a simple Http request I made, but data is displayed in console.log but loading is not getting dismissed

ngOnInit() {

    this.cartService.getProductDetails().subscribe(data =>{

        this.products = data;
        this.filter_products = this.products;

        console.log(this.products)  

    })

Upvotes: 1

Views: 723

Answers (1)

Derek S
Derek S

Reputation: 178

You are having multiple going at the same time, It's a race condition issue.. For this approach I would use a service that debounces the show & hide. this is the issue if you have multiple request going out at the same time or very close to each other..

Loading Service

import { Injectable } from '@angular/core';
import { LoadingController } from '@ionic/angular';
import { BehaviorSubject } from 'rxjs';
import { LoadingOptions } from '@ionic/core';
import { TranslateService } from '@ngx-translate/core';
import { debounceTime, distinctUntilChanged, filter, throttle } from 'rxjs/operators';
import { isNil } from 'lodash-es';

enum LoadingTypeEnum {
  show,
  hide,
  message
}

@Injectable({
  providedIn: 'root'
})
export class LoadingService {
  public loading$: BehaviorSubject<{ type: LoadingTypeEnum; data?: any }> = new BehaviorSubject<any>({ type: LoadingTypeEnum.hide });
  loadingState: { type: LoadingTypeEnum; data?: any } = null;
  public loading: HTMLIonLoadingElement = null;

  public async getLoader() {
    return await this.loadingController.getTop() || null
  };

  private async showLoading(opts: LoadingOptions) {
    if (!this.loading) {
      this.loading = await this.loadingController.create(opts);
      await this.loading.present();
    }
  }

  private async hideLoading() {
    if (this.loading) {
      await this.loading?.dismiss();
    }
    this.loading = null;
  }

  private async messageLoading(m: string) {
    if (this.loading) {
      this.loading.message = m
    }
  }

  constructor(private loadingController: LoadingController) {
    const l$ = this.loading$.pipe(distinctUntilChanged(), debounceTime(200));


    l$.pipe(filter(l => l.type === LoadingTypeEnum.show)).subscribe(l => this.showLoading(l.data));
    l$.pipe(filter(l => l.type === LoadingTypeEnum.hide)).subscribe(l => this.hideLoading());
    l$.pipe(filter(l => l.type === LoadingTypeEnum.message)).subscribe(l => this.messageLoading(l.data));
  }

  show(opts?: LoadingOptions) {
    if (isNil(opts)) opts = {
      message: 'Please Wait';
    };
    this.loading$.next({ type: LoadingTypeEnum.show, data: opts })
  }

  hide() {
    this.loading$.next({ type: LoadingTypeEnum.hide })
  }

  message(m: string) {
    this.loading$.next({ type: LoadingTypeEnum.message, data: m })
  }
}

Interceptor

@Injectable()
export class HttpRequestInterceptor implements HttpInterceptor {

  constructor(private loading: LoadingService) {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.loading.show();

    return next.handle(request).pipe(
      catchError(err => {
        if (err instanceof HttpErrorResponse) {
          switch ((<HttpErrorResponse>err).status) {
            case 401:
              console.log("401")

            default:
              return throwError(err);
          }
        } else {
          return throwError(err);
        }
      }),
      retryWhen(err => {
        let retries = 1;
        return err.pipe(
          delay(1000),
          tap(() => {
            // this.showRetryToast(retries);
          }),
          map(error => {
            if (retries++ === 3) {
              throw error; // Now retryWhen completes
            }
            return error;
          })
        );
      }),
      catchError(err => EMPTY),
      finalize(() => this.loading.hide()))
  }
}

Upvotes: 1

Related Questions