import { Inject , Injectable , Optional } from '@angular/core' ; import { NavigationCancel , NavigationEnd , NavigationError , NavigationStart , Router , RouterEvent } from '@angular/router' ; import { Observable , of } from 'rxjs' ; import { delay , distinctUntilChanged , filter , map , switchMap , tap } from 'rxjs/operators' ; import { InjectionToken , Type } from '@angular/core' ; import { ProgressBarService } from '../layout/progress/progress-bar.service' ; interface ProgressRouterConfig { id ? : string ; delay ? : number ; startEvents ? : Type < RouterEvent > [ ] ; completeEvents ? : Type < RouterEvent > [ ] ; } export const PROGRESS_ROUTER_CONFIG = new InjectionToken < ProgressRouterConfig > ( 'progressRouterConfig' ) ; @ Injectable ( { providedIn : 'root' } ) export class AppLoadingService { private readonly config : ProgressRouterConfig = { id : 'app' , delay : 100 , startEvents : [ NavigationStart ] , completeEvents : [ NavigationEnd , NavigationCancel , NavigationError ] } ; constructor ( private router , progressService , @ Optional ( ) @ Inject ( PROGRESS_ROUTER_CONFIG ) config ) { this . config = config ? { ... this . config , ... config } : this . config ; const progressBarInstance = progressService . getInstance ( this . config . id ) ; const startProgress = of ( { } ) . pipe ( delay ( this . config . delay ) , tap ( ( ) => progressBarInstance . start ( ) ) ) ; const completeProgress = of ( { } ) . pipe ( delay ( this . config . delay ) , tap ( ( ) => progressBarInstance . complete ( ) ) ) ; const filterEvents = [ ... this . config . startEvents , ... this . config . completeEvents ] ; this . router . events . pipe ( filter ( ( event ) => AppLoadingService . eventExists ( event , filterEvents ) ) , switchMap ( ( event ) => AppLoadingService . eventExists ( event , this . config . startEvents ) ? startProgress : completeProgress ) ) . subscribe ( ) ; } /**
     * Function which shows if the router is pending.
     */ public isNavigationPending : Observable < boolean > = this . router . events . pipe ( filter ( ( event ) => AppLoadingService . isConsideredEvent ( event ) ) , map ( ( event ) => AppLoadingService . isNavigationStart ( event ) ) , distinctUntilChanged ( ) ) ; private static isConsideredEvent ( event ) { return AppLoadingService . isNavigationStart ( event ) || AppLoadingService . isNavigationEnd ( event ) ; } private static isNavigationStart ( event ) { return event instanceof NavigationStart ; } private static isNavigationEnd ( event ) { return event instanceof NavigationEnd || event instanceof NavigationCancel || event instanceof NavigationError ; } static eventExists ( routerEvent , events ) { let res = false ; events . map ( ( event ) => res = res || routerEvent instanceof event ) ; return res ; } }