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) ); }