Thursday, 1 April 2021

How to implement a global loader in Angular

I have a global loader which is implemented like this:

CoreModule:

router.events.pipe(
  filter(x => x instanceof NavigationStart)
).subscribe(() => loaderService.show());

router.events.pipe(
  filter(x => x instanceof NavigationEnd || x instanceof NavigationCancel || x instanceof NavigationError)
).subscribe(() => loaderService.hide());

LoaderService:

@Injectable({
    providedIn: 'root'
})
export class LoaderService {

    overlayRef: OverlayRef;
    componentFactory: ComponentFactory<LoaderComponent>;
    componentPortal: ComponentPortal<LoaderComponent>;
    componentRef: ComponentRef<LoaderComponent>;

    constructor(
        private overlay: Overlay,
        private componentFactoryResolver: ComponentFactoryResolver
    ) {
        this.overlayRef = this.overlay.create(
            {
                hasBackdrop: true,
                positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically()
            }
        );

        this.componentFactory = this.componentFactoryResolver.resolveComponentFactory(LoaderComponent);

        this.componentPortal = new ComponentPortal(this.componentFactory.componentType);
    }

    show(message?: string) {
        this.componentRef = this.overlayRef.attach<LoaderComponent>(this.componentPortal);
        this.componentRef.instance.message = message;
    }

    hide() {
        this.overlayRef.detach();
    }
}

When running with Angular 7.0.2, the behavior (which I wanted) was:

  • Show loader while resolving data attached to a route, and while loading a lazy module
  • Don't show loader when navigating to a route without any resolver

I have updated to Angular 7.2, now the behavior is:

  • Show loader while resolving data attached to a route, and while loading a lazy module
  • Show the Overlay whithout the LoaderComponent when navigating to a route without any resolver

I have added some logs on the NavigationStart and NavigationEnd events and I found that NavigationEnd is triggered immediately after NavigationStart (which is normal), while Overlay disappears about 0.5s after.

I have read the CHANGELOG.md but I found nothing that might explain this problem. Any idea is welcome.

Edit:

After further research, I have restored the previous behavior by setting package.json like this:

"@angular/cdk": "~7.0.0",
"@angular/material": "~7.0.0",

instead of this:

"@angular/cdk": "~7.2.0",
"@angular/material": "~7.2.0",

I have identified the faulty commit which has been released in version 7.1.0 and I posted my problem on the related GitHub issue. It fixes the fade out animation of the Overlay.

What is the v7.1+ compliant way to get the desired behavior? According to me, the best thing to do would be: show the loader only when necessary, but NavigationStart doesn't hold the needed information. I'd like to avoid ending up with some debounce behavior.



from How to implement a global loader in Angular

No comments:

Post a Comment