Explain Codes LogoExplain Codes Logo

Show loading screen when navigating between routes in Angular 2

javascript
loading-screen
rxjs
navigation
Alex KataevbyAlex Kataev·Aug 15, 2024
TLDR

Implement a loading indicator in Angular by hooking onto the Router's navigation events. Use NavigationStart and NavigationEnd to control the display and hiding of the loading screen. Here is a concise example:

import { Component } from '@angular/core'; import { Router, Event, NavigationStart, NavigationEnd } from '@angular/router'; @Component({ selector: 'app-root', template: ` <div *ngIf="loading">Loading...</div> <router-outlet></router-outlet> `, styles: [` div { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: flex; justify-content: center; align-items: center; z-index: 1000; } `] }) export class AppComponent { loading = false; constructor(router: Router) { router.events.subscribe(event => this.loading = event instanceof NavigationStart || !(event instanceof NavigationEnd)); } }

In this loading toggles true or false based on the event type. This ensures the loading screen displays during route changes, enhancing UX without overcomplicating application logic.

Taking a deep swim in the seas of dynamic loading indicators

Solving awkward silences with Subjects

Instead of merely toggling a boolean, here's a fresh alternative - using a Subject to manage the visibility of the loading spinner - the reactive way.

import { BehaviorSubject } from 'rxjs'; loadingSubject = new BehaviorSubject<boolean>(false); // Like the TV show, but without the Upside Down loading$ = this.loadingSubject.asObservable(); // $ - because we are cool

Bind this loading$ in your template with the async pipe for a reactive seamless experience, smoother than a jazz saxophone riff. 🎷

Running outside Angular's Zone, literally

Boost performance and keep unnecessary change detection cycles at bay by running the spinner's display logic outside Angular's Zone using NgZone.

import { NgZone } from '@angular/core'; constructor(router: Router, private zone: NgZone) { router.events.subscribe(event => { if (event instanceof NavigationStart) { this.zone.runOutsideAngular(() => this.loadingSubject.next(true)); } else if (event instanceof NavigationEnd || event instanceof NavigationCancel || event instanceof NavigationError) { this.zone.runOutsideAngular(() => this.loadingSubject.next(false)); } }); }

This is like sneaking out of the house at night, except Angular won't ground you. 😈😂

RPG Character Customization, but for your loading screen

Nothing beats customization. Assert your dominance with Renderer2 when it comes to interacting with DOM elements.

import { Renderer2, ElementRef, ViewChild } from '@angular/core'; @ViewChild('spinner', { static: true }) spinner: ElementRef; // Not the fidget spinner! constructor(private renderer: Renderer2) {} toggleSpinner(isVisible: boolean): void { const action = isVisible ? this.renderer.addClass : this.renderer.removeClass; action(this.spinner.nativeElement, 'show-spinner'); }

Now watch your loading spinner dance to your tunes!

Stand on the shoulder of giants with ngx-loading-bar

Why reinvent the wheel when ngx-loading-bar gives you a sleek loading bar with just a sprinkling of setup?

// In your app.module.ts import { LoadingBarRouterModule } from '@ngx-loading-bar/router'; @NgModule({ imports: [ LoadingBarRouterModule ], }) export class AppModule {}

Just put <ngx-loading-bar></ngx-loading-bar> in the slot you want to see the loading bar and let it do its magic trick! 🎩🐇

Comprehensive strategies for enhanced loading screens

CanDeactivate: Your secret navigation sheriff

Utilize Angular's CanDeactivate guard to keep tight control over navigation based on user actions or form state.

Battling delays and laughing at errors like a pro

Use NavigationCancel and NavigationError events to handle scenarios where navigation might delay or fail.

router.events.subscribe(event => { if (event instanceof NavigationCancel || event instanceof NavigationError) { this.handleError(event); } }); handleError(event): void { console.error(`Navigation Error: ${event}`); this.loadingSubject.next(false); // Switch off loading, we've had enough! // friendly way of saying "Oops! Something went wrong." }

Becoming efficient with RxJS Operators

Use RxJS's take(1) operator to only subscribe to the first instance of an event and avoid the plague of multiple subscriptions.

Style and substance with CSS

Use CSS classes or style bindings for visually toggling visibility.

.spinner-container { transition: opacity 0.3s ease; // Smooth, just like your favorite chocolate. }