Angular - Add loading spinner

Table of Contents

Use Rxjs and Interceptor to show and hide loading spinner in Angular when processing API.

The technique is same as building a lightbox effect Modal.

Implementation

Add service

  • Generate service through command ng g s loading
  • loading.service.ts
    private _loading = new BehaviorSubject<boolean>(false);
    public readonly $loading = this._loading.asObservable();
    
    show() {
      this._loading.next(true);
    }
    
    hide() {
      this._loading.next(false);
    }
    

Add component

  • Generate component through command ng g c loading

  • loading.component.html

    • Show the loader only when loading$ is true.
    • AsyncPipe (| async) use to unwrap a value from an asynchronous primitive. Observable is an asynchronous primitive, it can subscribe and upwrap the value through async pipe.
    <div class="backdrop" *ngIf="loading$ | async">
      <div class="loader"></div>
    </div>
    
  • loading.component.ts

    loading$: Observable<boolean> = this._loadingService.loading$;
    
    constructor(private _loadingService: LoadingService) { }
    
  • loading.component.scss

    .backdrop {
      position: absolute;
      top: 0;
      left: 0;
      margin: auto;
      width: 100%;
      height: 100%;
      background: rgba(0,0,0,0.5);
      z-index: 20000;
      .loader {
        position: absolute;
        inset: 0;
        border: 16px solid var(--light);
        border-top: 16px solid var(--primary);
        border-radius: 50%;
        width: 120px;
        height: 120px;
        margin: auto;
        animation: spin 2s linear infinite;
      }
    }
    
    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }
    

Add Interceptor

Start loading before sending the request and stop loading after the request completed.

  • Generate interceptor through command ng g interceptor network
  • network.interceptor.ts
    import { LoadingService } from './loading.service';
    import { finalize } from 'rxjs/operators';
    
    constructor(private _loadingService: LoadingService) {}
    
    intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
      this._loadingService.show();
      return next.handle(request).pipe(
        finalize(() => this._loadingService.hide())
      );
    }
    
    • app.modules.ts
    providers: [{
      provide: HTTP_INTERCEPTORS,
      useClass: NetworkInterceptor,
      multi: true
    }],
    

Build a popup modal

The implementation we had just done is similar to lightbox effect. We can also apply methods above to build a modal.

Modal

References

Add an Angular Loading Spinner with RxJS and Material