Federico
Federico

Reputation: 455

How to show spinner only if data are fetched from Http service?

I have to show a spinner only during http service call, and dismiss it when my component receives data.

I wrote a little cache service in order to fetch data from http service only the first time, and load that data from the cache during every other call, avoiding to call another time the http service.

The service is working as expected,but what if I'd like to show the spinner only during the http call and not when data are fetched from cache?

This is my component's code, it works when getReviewsCategory(this.id) method of my service calls http service, but when it fetches from cache the spinner is never dismissed. Data are loaded in correct way in the background, but the spinner keeps going.

presentLoading() method is in ngOnInit so it's called everytime, what if I want to call it only when data are fetched from cache? How my component could know it?


    ngOnInit() {
       this.presentLoading();
       this.CategoryCtrl();
     }

     CategoryCtrl() {
       this.serverService.getReviewsCategory(this.id)
       .subscribe((data) => {
         this.category_sources = data['value'];
         this.stopLoading();
       });
     }

     async presentLoading() {
       const loadingController = this.loadingController;

       const loadingElement = await loadingController.create({
         spinner: 'crescent',
       });
       return await loadingElement.present()
     }

     async stopLoading() {
       return await this.loadingController.dismiss();
     }

   }

EDIT1: this is the CacheService:


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

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

      constructor() { }

      private _cache = {};

      isCashed(url: string) {
        return this._cache[url];
      }

      getData(url: string) {
        return this._cache[url];
      }

      setData(url) {
        return (data) => {
          if (data && (data instanceof Error) === false) {
            this._cache[url] = data;
          };
        }
      }

      reset() {
        this._cache = {};
      }
    }

And this is the server service's method:



     getReviewsCategory(cat_id) : Observable<any> {
      if (this._c.isCashed(url)) {
            return of(this._c.getData(url));
          }else{
            var modeapp = window.sessionStorage.modeapp;
            var typemodeapp = typeof(window.sessionStorage.modeapp);
            if (modeapp === "online") {
              let promise = new Promise ((resolve, reject) => {
                this.httpNative.get(url, {}, {}).
                then((data) => {
                  let mydata = JSON.parse(data.data);
                  console.log("Data from HTTP: ");
                  console.log(mydata);
                  resolve(mydata);
                }, (error) => {
                  console.log("error in HTTP");
                  reject(error.error);
               }
              );
            });
              var observable = from(promise);
          }
        }
        return observable
        .pipe(
          tap(this._c.setData(url))
        );

Upvotes: 1

Views: 271

Answers (2)

AndrWeisR
AndrWeisR

Reputation: 1226

You can use an HttpInterceptor class to intercept all http calls, and in the intercept method, you can stop and start a spinner.

Broadly speaking, the structure is:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Start the spinner.
    return next.handle(req).pipe(
        map((event: HttpEvent<any>) => {
            if (event instanceof HttpResponse) {
                // Stop the spinner
            }
            return event;
        })
    );

Upvotes: 0

Narshe
Narshe

Reputation: 466

I can see you're returning an observable from the service, you can try the following to see if this helps.

     CategoryCtrl() {
       this.serverService.getReviewsCategory(this.id)
       .subscribe((data) => {
         this.category_sources = data['value'];
         this.stopLoading();
       },
       (error) => console.log(error),
       () => this.stopLoading(); // This always execute
     );}

Docs: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-subscribe

However, I believe the problem may come from the object you're calling .dismiss() from. You should be calling dismiss on the instance of the element and not the object itself.

let loadingElement: Loading = null;

async presentLoading() {
   const loadingController = this.loadingController;
   this.loadingElement = await loadingController.create({
     spinner: 'crescent',
   });
   return await loadingElement.present()
}

async stopLoading() {
   return await this.loadingElement.dismiss();
}

Upvotes: 1

Related Questions