Show Loading Screen When Navigating Between Routes in Angular 2

Show loading screen when navigating between routes in Angular 2

The current Angular Router provides Navigation Events. You can subscribe to these and make UI changes accordingly. Remember to count in other Events such as NavigationCancel and NavigationError to stop your spinner in case router transitions fail.

app.component.ts - your root component

...
import {
Router,
// import as RouterEvent to avoid confusion with the DOM Event
Event as RouterEvent,
NavigationStart,
NavigationEnd,
NavigationCancel,
NavigationError
} from '@angular/router'

@Component({})
export class AppComponent {

// Sets initial value to true to show loading spinner on first load
loading = true

constructor(private router: Router) {
this.router.events.subscribe((e : RouterEvent) => {
this.navigationInterceptor(e);
})
}

// Shows and hides the loading spinner during RouterEvent changes
navigationInterceptor(event: RouterEvent): void {
if (event instanceof NavigationStart) {
this.loading = true
}
if (event instanceof NavigationEnd) {
this.loading = false
}

// Set loading state to false in both of the below events to hide the spinner in case a request fails
if (event instanceof NavigationCancel) {
this.loading = false
}
if (event instanceof NavigationError) {
this.loading = false
}
}
}

app.component.html - your root view

<div class="loading-overlay" *ngIf="loading">
<!-- show something fancy here, here with Angular 2 Material's loading bar or circle -->
<md-progress-bar mode="indeterminate"></md-progress-bar>
</div>

Performance Improved Answer: If you care about performance there is a better method, it is slightly more tedious to implement but the performance improvement will be worth the extra work. Instead of using *ngIf to conditionally show the spinner, we could leverage Angular's NgZone and Renderer to switch on / off the spinner which will bypass Angular's change detection when we change the spinner's state. I found this to make the animation smoother compared to using *ngIf or an async pipe.

This is similar to my previous answer with some tweaks:

app.component.ts - your root component

...
import {
Router,
// import as RouterEvent to avoid confusion with the DOM Event
Event as RouterEvent,
NavigationStart,
NavigationEnd,
NavigationCancel,
NavigationError
} from '@angular/router'
import {NgZone, Renderer, ElementRef, ViewChild} from '@angular/core'


@Component({})
export class AppComponent {

// Instead of holding a boolean value for whether the spinner
// should show or not, we store a reference to the spinner element,
// see template snippet below this script
@ViewChild('spinnerElement')
spinnerElement: ElementRef

constructor(private router: Router,
private ngZone: NgZone,
private renderer: Renderer) {
router.events.subscribe(this._navigationInterceptor)
}

// Shows and hides the loading spinner during RouterEvent changes
private _navigationInterceptor(event: RouterEvent): void {
if (event instanceof NavigationStart) {
// We wanna run this function outside of Angular's zone to
// bypass change detection
this.ngZone.runOutsideAngular(() => {
// For simplicity we are going to turn opacity on / off
// you could add/remove a class for more advanced styling
// and enter/leave animation of the spinner
this.renderer.setElementStyle(
this.spinnerElement.nativeElement,
'opacity',
'1'
)
})
}
if (event instanceof NavigationEnd) {
this._hideSpinner()
}
// Set loading state to false in both of the below events to
// hide the spinner in case a request fails
if (event instanceof NavigationCancel) {
this._hideSpinner()
}
if (event instanceof NavigationError) {
this._hideSpinner()
}
}

private _hideSpinner(): void {
// We wanna run this function outside of Angular's zone to
// bypass change detection,
this.ngZone.runOutsideAngular(() => {
// For simplicity we are going to turn opacity on / off
// you could add/remove a class for more advanced styling
// and enter/leave animation of the spinner
this.renderer.setElementStyle(
this.spinnerElement.nativeElement,
'opacity',
'0'
)
})
}
}

app.component.html - your root view

<div class="loading-overlay" #spinnerElement style="opacity: 0;">
<!-- md-spinner is short for <md-progress-circle mode="indeterminate"></md-progress-circle> -->
<md-spinner></md-spinner>
</div>

How to display loading screen while routing using navigation in Angular2?

I found the solution. Posting it if anyone needs it in future.

This is what I did... I added setTimeout functionality to the app.component.ts as

import {
Component
} from '@angular/core';
import {
Router,
// import as RouterEvent to avoid confusion with the DOM Event
Event as RouterEvent,
NavigationStart,
NavigationEnd,
NavigationCancel,
NavigationError
} from '@angular/router';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./loadingCSS.css']
})

export class AppComponent {
// Sets initial value to true to show loading spinner on first load
loading = true;

constructor(private router: Router) {
router.events.subscribe((event: RouterEvent) => {
this.navigationInterceptor(event);
});
}

// Shows and hides the loading spinner during RouterEvent changes
navigationInterceptor(event: RouterEvent): void {
if (event instanceof NavigationStart) {
this.loading = true;
}
if (event instanceof NavigationEnd) {
setTimeout(() => { // here
this.loading = false;
}, 2000);
}

// Set loading state to false in both of the below events to hide the spinner in case a request fails
if (event instanceof NavigationCancel) {
setTimeout(() => { // here
this.loading = false;
}, 2000);
}
if (event instanceof NavigationError) {
setTimeout(() => { // here
this.loading = false;
}, 2000);
}
}


And changed the HTML as

<div class="loading-overlay" *ngIf="loading">
Loading<span class="d">.</span><span class="d d-2">.</span><span class="d d-3">.</span>
</div>
<div *ngIf="!loading">
<router-outlet></router-outlet>
</div>

How to show a spinner loader between the one route to another route in angular 4, I am geeting events but not able to show the loader

Remove NavigationCancel and NavigationError, If you are not using route guards in your app, You will get NavigationCancel event only if you have route guards and that return false during navigation. You can check that by passing {enableTracing : true} object in routerModule

constructor(private router: Router) {
router.events.subscribe((event: Event) => {
this.navigationInterceptor(event);
});
}

navigationInterceptor(event: Event): void {
if (event instanceof NavigationStart) {
this.loader = true;
}
if (event instanceof NavigationEnd) {
// Hide loading indicator
this.timeout = setTimeout(() => {
clearTimeout(this.timeout);
this.loader = false;
}, 1000);
}
// if (event instanceof NavigationCancel) {
// this.loader = false;
// }
// if (event instanceof NavigationError) {
// console.log(event);
// this.loader = false;
// }

}

Example:https://stackblitz.com/edit/angular-spinner-example-bcedjq

Problem when loading routes from DB dynamically in angular 2

But when I refresh the page or I write directly the url in the adress bar the route does not work, why?

There are no additional routes in your application yet. You would have to try to load them on boot time before application is fully started.

You can try to use APP_INITIALIZER (https://hackernoon.com/hook-into-angular-initialization-process-add41a6b7e) or you will have to expose public variable before angular script loads the application, and append required enties directly in routing configuration.



Related Topics



Leave a reply



Submit