简体   繁体   中英

Angular 5 Loading Spinner on Startup with Lazy-Loaded Route/Module

In Angular 5, how can I show a loading spinner on app startup if the requested route/module is lazy loaded ?

My first idea was to simply include the spinner code inside the <app-root> tag (see this question , specifically the comment by Christophe Vidal on the accepted answer).

This works fine, however , a problem arises if on app startup, the requested route happens to be one that corresponds to a route/module that is lazy loaded .

In that case, the spinner will initially display as expected, however will disappear too early . More specifically, when the spinner disappears, there still is noticeable time left before the actual content appears.

I assume this delay is due to the lazy loading and my spinner in <app-root> already being overwritten even though there is no content yet?

index.html

<app-root>
    <div class="loading">
        <!-- loading spinner here -->
    </div>
</app-root>

How would you go about showing a loading spinner in this scenario?

Note: I am not asking about showing a spinner when getting data via http, I am asking about showing a spinner on startup of the app.

My take on this would be to subscribe to the Angular router events in your app root app.component.ts on initialization. However, it is important to note that this will not only result in your spinner being displayed while your lazy loaded component is loading, but also whenever you navigate to any route. (Which may not be what you desire)

ngOnInit(){
 router.events.subscribe( (event: Event) => {

            if (event instanceof NavigationStart) {
                /*Display your spinner*/
            }

            if (event instanceof NavigationEnd) {
                /*Hide your spinner*/
            }
        });
}

***update***

I found you can bind to the <router-outlet> and that will allow you to determine what component is being loaded. I know the struggle was to get the spinner to only stop spinning once the lazy loaded component loads. By binding to the router-outlet in your app.component.ts you can determine what component is being loaded and at that point stop the spinner.

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'my-app',
  template: `<router-outlet #outlet></router-outlet>`
})
export class AppComponent implements AfterViewInit {
  @ViewChild(RouterOutlet)
  public outlet: RouterOutlet;

  public ngAfterViewInit(): void {
    this.outlet.activateEvents.subscribe((component) => {
      if (component.__proto__.constructor.name === 'myLazyComponent') {
        //Hide Spinner
      }
    });
  }
}

There are router events : RouteConfigLoadStart and RouteConfigLoadEnd so the code would be:

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'my-app',
  template: `<app-spinner *ngIf="showSpinner"></app-spinner><router-outlet></router-outlet>`
})
export class AppComponent implements AfterViewInit {
  showSpinner: boolean = false;

  constructor(private router: Router) {
      this.router.events.subscribe(
              event => {
                if(event instanceof RouteConfigLoadStart) {
                  showSpinner = true;
                  return;
                }
                if(event instanceof RouteConfigLoadEnd) {
                  showSpinner = false;
                  return;
                }
          }
      );
   }
}

The app-spinner component can be some kind of overlay with spinning icon in the middle of browser window.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM