Loading screen displayed while transitioning between routes within Angular

I have been struggling to implement a loading spinner in my project. How can I display a loading screen when changing routes in Angular?

Here is the HTML code snippet:

<div *ngIf="showLoadingIndicator" class="spinner"></div>

Below is the component.ts file content:

import { Component, OnInit } from '@angular/core';
import { Event, Router, NavigationStart, NavigationEnd,NavigationCancel,
  NavigationError } from '@angular/router';


@Component({
  selector: 'app-home-page',
  templateUrl: './home-page.component.html',
  styleUrls: ['./home-page.component.scss']
})
export class HomePageComponent implements OnInit {
  
  loading = true
  showLoadingIndicator = true;


  constructor(public router: Router) {
    this.router.events.subscribe((routerEvent: Event) => {
      if (routerEvent instanceof NavigationStart) {
        this.showLoadingIndicator = true
      }
      if (routerEvent instanceof NavigationEnd) {
        this.showLoadingIndicator = false
      }
      if (routerEvent instanceof NavigationError){
        this.showLoadingIndicator = false
      }
      if(routerEvent instanceof NavigationCancel){
        this.showLoadingIndicator = false
      }
    });

  }

This is the relevant CSS styling for the spinner:

.spinner {
  border :16px solid silver;
  border-top: 16px solid #337AB7;
  border-radius: 50%;
  width: 80px;
  height: 80px;
  animation: spin 700ms linear infinite;
  top: 50%;
  left: 50%;
  position: absolute;

}
@keyframes spin {
  0% {transform: rotate(0deg)}
  100%{transform:  rotate(-360deg)}
}

If anyone can provide insight into what might be causing the issue, I would greatly appreciate it. Thank you in advance.

Answer №1

Position the spinner at the same level as the Router outlet. You can have multiple spinners in your application, so the placement of the spinner will vary based on your specific use case.

In the class, create an observable with the router events, filter the stream to only emit start/termination events, and map them to a boolean value.

You can also add a side effect to display a label when tapping on the spinner, but this is optional. Observables and side effects are subject to lengthy discussions, but in this scenario, the side effects are minimal, leading to cleaner code without needing manual subscribe/unsubscribe manipulation of the observable.

CSS details have been left out for conciseness.

<theme-navbar>
</theme-navbar>
<loading-spinner
    *ngIf="loading | async; else routerOutlet"
    label="{{status}}"
    size="extra-large"
></loading-spinner>
<ng-template #routerOutlet>
    <router-outlet></router-outlet>
</ng-template>

The corresponding class would be:

import { Component, OnInit, inject } from '@angular/core';
import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
import { filter, map, tap } from 'rxjs';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
    
    status = '';

    loading = inject(Router).events.pipe(
        filter((e) =>[ // only react to start and finish events
            NavigationStart,
            NavigationEnd,
            NavigationError,
            NavigationCancel
        ].some((constructor) => e instanceof constructor)),
        map((e) => e instanceof NavigationStart),
        // this line saves us to have to manually subscribe to the stream
        tap(e=>{this.status = e ? 'navigating' : 'done'})
    );
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble finding the "make:migration" command in Adonis 5 - any suggestions?

After reviewing the introductory documentation for Adonis Js5, I attempted to create a new API server. However, when compiling the code using "node ace serve --watch" or "node ace build --watch", I kept receiving an error stating "make:migration command no ...

Is the Packery image grid only functional when the background image is specified in CSS and not in JavaScript? Perhaps we need to look into using Await/Sem

I've successfully implemented a packery image grid that is responsive and functional when the background image in the .item-content section is defined in the CSS file: http://codepen.io/anon/pen/eJdapq .item-content { width: 100%; height: 100%; ...

Strikethrough feature not specified on the website

Check out this unique website that showcases text with a strikethrough. Interestingly, I couldn't find any mention of it in the CSS or HTML code. Here is a snippet from the code: <div style="width:100%;height:259px;background-image: url('< ...

Ways to add a React Router Link to a Material UI TableRow

When attempting to incorporate a Link component from React Router Dom into my Material UI TableRow, I encountered an issue. <TableRow component={Link as any} to={`/company/${company.id}`} className="clt-row" key={company.id}> The error message I re ...

The issue with Angular 2's router.navigate not functioning as expected within a nested JavaScript function

Consider the app module: import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angul ...

Retrieving text from a draggable div using jQuery

I have a draggable div that I can move over another element with the class .outerDiv which contains text content. Is there a way for me to retrieve the text from .outerDiv that overlaps with the draggable div? $(".outerDiv .isStore").draggable({ contain ...

Cannot locate module using absolute paths in React Native with Typescript

I recently initiated a new project and am currently in the process of setting up an absolute path by referencing this informative article: https://medium.com/geekculture/making-life-easier-with-... Despite closely following the steps outlined, I'm en ...

What is the best way to distribute stroke width evenly on a rounded hexagon in an SVG?

I created a rounded hexagon with stroke width, but the top and bottom curves appear darker. Does anyone know how to evenly distribute the stroke width along the border? Here is my SVG code: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewbox ...

What is the process behind managing today's Google image of the day?

After coming across the javascript picture control on the Google search page, I became interested in replicating it myself. The feature zooms in on a picture when hovering over it, but I couldn't locate the HTML code they were using for it. Is there ...

Utilizing Jquery cycle to overlay a div on top of a scrolling image

Hey there! I'm currently using the jquery.cycle.all.js plugin for my website. I've encountered an issue where I want to position a menu div on top of an image slider. The menu is in the correct location, but unfortunately, it's hidden benea ...

How can you retrieve the preceding sibling using an Angular directive?

Currently, I am utilizing ELEMENTREF to interact with the DOM via Renderer2. Allow me to provide a simple example: import { Directive, Renderer2, ElementRef } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export c ...

How about, "Enhance your website navigation with a sleek anchor

After many attempts to implement smooth scrolling on my Bootstrap project, I have tried numerous Youtube tutorials and Google search results without any success. The latest attempt I made was following this Stack Overflow post Smooth scrolling when clickin ...

jQuery counter no longer updates when scrolling

I'm having trouble with my jQuery counting function when using the scroll feature on a specific div ID. The numbers freeze if I keep scrolling before they finish updating on the screen. Whenever I scroll to the defined div ID, the counting function k ...

How can I merge these two Observables in Angular to create an array of objects?

Let's say we are working with two different datasets: student$ = from([ {id: 1, name: "Alex"}, {id: 2, name: "Marry"}, ]) address$ = from([ {id: 1, location: "Chicago", sid: 1}, {id: 2, location: &qu ...

Ways to showcase alerts on dashboard

I have a specific need to incorporate a notification bell icon in my dashboard. Essentially, I want the user to be alerted about any actions that they need to take through this notification system. For example, if a task is rejected, approved, or pending v ...

The type '{}' does not contain a property named 'map'

Recently delving into TypeScript, and I'm curious about the process of typing an axios response when storing it in a state variable. I've initiated a basic API call from App.tsx, which returns the following object: {data: {…}, status: 200, s ...

Locate and modify a single item in a list using NGRX

I have an array of items stored in my ngrx/store. When the user clicks on a button, I need to retrieve a specific item based on its id and update its properties without using ngxr/entities. I have managed to achieve this functionality in my current imple ...

Tips for assigning a class to a div based on the route in Angular

In my angular template, I have a basic ng-repeat with some div elements. Now, I am looking to add a class to a specific div if the $routeParams.userId matches the id of the object in the loop. You can refer to the second line of code below for clarificatio ...

Ways to obtain the scrollWidth and offSetWidth of a div that is being utilized as an ngx-datatable-cell-template within an ngx-datatable

How can I retrieve the scrollWidth and offSetWidth of a div that is included in a child component being loaded as an ngx-datatable-cell-template inside ngx-datatable? I am consistently receiving values of 0. I have added a template variable for the div el ...

The issue with Internet Explorer failing to adhere to the restrictions set on maximum width and

I'm attempting to scale my images precisely using CSS: HTML: <div id="thumbnail-container"> <img src="sample-pic.jpg"/> </div> CSS: #thumbnail-container img { max-height: 230px; max-width: 200px; } In this scenario, ...