For example, we want to show loading spinner inside our appliction component trees. Because we might trigger loading spinner anywhere inside our application, therefore, we need to use a loading.service.ts to communciate between different compnents.
loading.service.ts:
import {Injectable} from '@angular/core'; import {BehaviorSubject, Observable, of} from 'rxjs'; import {concatMap, finalize, tap} from 'rxjs/operators'; @Injectable() export class LoadingService { private loadingSubject = new BehaviorSubject<boolean>(false); loading$: Observable<boolean> = this.loadingSubject.asObservable(); loadingOn() { this.loadingSubject.next(true); } loadingOff() { this.loadingSubject.next(false); } showLoaderUntilCompleted<T>(obs$: Observable<T>): Observable<T> { return of(null) .pipe( tap(() => this.loadingSubject.next(true)), concatMap(() => obs$), finalize(() => { this.loadingSubject.next(false); }) ); } }
Component:
import { Component, OnInit } from '@angular/core'; import {Observable} from 'rxjs'; import {LoadingService} from './loading.service'; @Component({ selector: 'loading', template: '<div class="spinner-container" *ngIf="loading$ | async"><mat-spinner></mat-spinner></div>' }) export class LoadingComponent implements OnInit { loading$ : Observable<boolean>; constructor(private loadingService: LoadingService) { } ngOnInit() { this.loading$ = this.loadingService.loading$; } }
The most important thing to understand here is the function: showLoaderUntilComplete(obs$).
It takes a Observable, because we want to wait 'obs$' to complete, therefore, we use 'concatMap', it executes observable one by one, then we use 'finalize' operator, it will execute callback function when the observable completes. Here means waiting 'obs$' to be completed.
How to use it?
courses.service.ts
private subject = new BehaviorSubject<Course[]>([]); courses$ = this.subject.asObservable(); private loadAllCourses() { const loadCourses$ = this.http.get<Course[]>('/api/courses') .pipe( map(response => response["payload"]) ); this.loading.showLoaderUntilCompleted(loadCourses$) .subscribe( courses => this.subject.next(courses) ); }