Search code examples
angularngx-spinner

Angular 9 | NgxSpinner: Overriden methods aren't working


I'm triying to override show and hide methods from NgxSpinner to prevent the short-time display spinners when the process lasts too little time.

This is my code in the class that extends NgxSpinnerService

    import { Injectable } from '@angular/core';
    import { NgxSpinnerService, Spinner } from 'ngx-spinner';
    
    @Injectable({
        providedIn: 'root'
    })
    
    export class SpinnerService extends NgxSpinnerService {
        constructor() { super(); }
        private onDisplay: boolean = false;
    
        show (name?: string, spinner?: Spinner): Promise<unknown> {
            this.onDisplay = true;
            setTimeout(() => {
                console.log(`showing ${name} | onDisplay ${this.onDisplay}`);
                if (this.onDisplay) return super.show(name, spinner);
            }, 300);
            return null;
        }
    
        hide (name?: string, debounce?: number): Promise<unknown> {
            this.onDisplay = false;
            return super.hide(name, debounce);
        }
    }

And this is a fragment of the component from where I'm calling the method from

    constructor(
        private _graphService: GraphsService,
        private _medicinesService: MedicinesServices,
        private _notification: NotificationService,
        private fb: FormBuilder,
        private spinner: SpinnerService
    ) { }

    ngOnInit (): void {
        this.init();
    }

    private init () {
        this.spinner.show('component');
        this._medicinesService.getAllGrupedBy().subscribe(
            (data) => {
                ...
                this.loadData();
            },
            (error) => {
                this._notification.showErrorToast(error.errorCode);
                this.spinner.hide('component');
            }
        );
    }

    private loadData (): void {
        this.spinner.show('component');
        if (!this.selectedOption) this.selectedOption = this.options[0];
        this.getData().subscribe(
            (data) => {
                ...
                this.spinner.hide('component');
            },
            (error) => {
                this.spinner.hide('component');
                this._notification.showErrorToast(error.errorCode);
            }
        );
    }

HTML in the app.component.html

        <div [ngClass]="{ 'loading-container': !isMobileScreen }">
            <ngx-spinner [name]="spinnersConf.component.name" [fullScreen]="false" [bdColor]="spinnersConf.component.bgColor">
                <p style="font-size: 20px; color: white">{{ spinnersConf.component.text | translate }}</p>
            </ngx-spinner>
        </div>

The console appears in the developers tool window, but the spinner won't show. However, if I call the show method from the NgxSpinnerService it will appear without problems.

Am I having any error on my service?


Solution

  • First create a common component for loader whenever you call API that component loader you will see.

    After creation of loader component add or create this file loader.interceptor.ts and loader.service.ts for showing spinner.

    loader.interceptor.ts

    import { Injectable } from "@angular/core";
    import {
      HttpEvent,
      HttpHandler,
      HttpInterceptor,
      HttpRequest
    } from "@angular/common/http";
    import { Observable } from "rxjs";
    import { finalize } from "rxjs/operators";
    import { LoaderService } from "./loader.service";
    import { NgxSpinnerService } from "ngx-spinner";
    @Injectable()
    export class LoaderInterceptor implements HttpInterceptor {
      constructor(
        public loaderService: LoaderService,
        private spinner: NgxSpinnerService
      ) {}
      intercept(
        req: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
        this.loaderService.show();
        return next.handle(req).pipe(finalize(() => this.loaderService.hide()));
      }
    }
    

    loader.service.ts

    import { Injectable } from "@angular/core";
    import { NgxSpinnerService } from "ngx-spinner";
    import { Subject } from "rxjs";
    @Injectable()
    export class LoaderService {
      constructor(private spinner: NgxSpinnerService) {}
    
      isLoading = new Subject<boolean>();
      show() {
        this.isLoading.next(true);
        this.spinner.show();
      }
      hide() {
        this.isLoading.next(false);
        this.spinner.hide();
      }
    }
    

    loader.component.html

    <ngx-spinner bdColor="rgba(0, 0, 0, 0.8)" size="medium" color="#fff" type="square-jelly-box" [fullScreen]="true">
      <p style="color: white"> Loading... </p>
    </ngx-spinner>
    

    app.module.ts

    providers: [
        LoaderService,
        { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptor, multi: true }
    ]
    

    app.component.html

    <div *ngIf="isLoading | async">
      <app-loader></app-loader>
    </div>
    

    app.component.ts

    import { HttpClient } from "@angular/common/http";
    import { LoaderService } from "./loader/loader.service";
    
    constructor(private http: HttpClient, private loaderService: LoaderService) {}
    
      isLoading: Subject<boolean> = this.loaderService.isLoading;
    
      data: any = [];
    
      showData() {
        this.data = [];
        this.http.get("assets/dummyData.json").subscribe(data => {
          this.data = data['employees'];
        });
      }
    

    If you get stuck while doing this, you can visit my Stackblitz.

    Here is different different ngx-spinner if you want.