In this article, we will learn how to display loader/spinner on each HTTP calls in Angular 9.
Prerequisites:
- Basic knowledge of Angular
- Code editor like Visual Studio Code
Create a new Angular project by typing the following command in the VSCode terminal.
ng new loader
Now create a new custom Loader Component by typing the following command in the VSCode terminal.
ng g c loader
Now create a new Loader Service by typing the following command in the VSCode terminal.
ng g s loader/services/loader
Now create a new Loader Interceptor by typing the following command in the VSCode terminal.
ng g s loader/interceptors/loader-interceptor
Angular Interceptors are used to do some work for every single HTTP request or response.
Open the loader.service.ts file and add the code in it.
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class LoaderService { public isLoading = new BehaviorSubject(false); constructor() { } }
Open the loader-interceptor.service.ts file and add the code in it.
import { Injectable } from '@angular/core'; import { HttpResponse, HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs'; import { LoaderService } from '../services/loader.service'; @Injectable({ providedIn: 'root' }) export class LoaderInterceptorService implements HttpInterceptor { private requests: HttpRequest<any>[] = []; constructor(private loaderService: LoaderService) { } removeRequest(req: HttpRequest<any>) { const i = this.requests.indexOf(req); if (i >= 0) { this.requests.splice(i, 1); } this.loaderService.isLoading.next(this.requests.length > 0); } intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { this.requests.push(req); this.loaderService.isLoading.next(true); return Observable.create(observer => { const subscription = next.handle(req) .subscribe( event => { if (event instanceof HttpResponse) { this.removeRequest(req); observer.next(event); } }, err => { alert('Error: ' + err); this.removeRequest(req); observer.error(err); }, () => { this.removeRequest(req); observer.complete(); }); return () => { this.removeRequest(req); subscription.unsubscribe(); }; }); } }
Open the loader.component.css file and add the code in it.
.spinner { width: 40px; height: 40px; background-color: #333; margin: auto; -webkit-animation: sk-rotateplane 1.2s infinite ease-in-out; animation: sk-rotateplane 1.2s infinite ease-in-out; } @-webkit-keyframes sk-rotateplane { 0% { -webkit-transform: perspective(120px) } 50% { -webkit-transform: perspective(120px) rotateY(180deg) } 100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) } } @keyframes sk-rotateplane { 0% { transform: perspective(120px) rotateX(0deg) rotateY(0deg); -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg) } 50% { transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg) } 100% { transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); } } .LoaderWrap { position: fixed; top: 0; left: 0; z-index: 9999; background: rgba(0, 0, 0, .3); right: 0; bottom: 0; } .LoaderWrap .spinnerWrap { height: 100vh; display: flex; align-items: center; justify-content: center; }
Open the loader.component.html file and add the code in it.
<div class="LoaderWrap" [hidden]="!loading"> <div class="spinnerWrap"> <div class="spinner"></div> </div> </div>
Open the loader.component.ts file and add the code in it.
import { Component, OnInit } from '@angular/core'; import { LoaderService } from './services/loader.service'; @Component({ selector: 'app-loader', templateUrl: './loader.component.html', styleUrls: ['./loader.component.css'] }) export class LoaderComponent implements OnInit { loading: boolean; constructor(private loaderService: LoaderService) { this.loaderService.isLoading.subscribe((x) => { this.loading = x; }); } ngOnInit(): void { } }
Open the app.component.html file and add the code in it.
<app-loader></app-loader> <router-outlet></router-outlet>
Open the app.component.ts file and add the code in it.
import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(public http: HttpClient) { this.http.get('https://reqres.in/api/users') .subscribe((result) => { console.log(result); }); } }
Open the app.module.ts file and add the code in it.
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { LoaderComponent } from './loader/loader.component'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { LoaderService } from './loader/services/loader.service'; import { LoaderInterceptorService } from './loader/interceptors/loader-interceptor.service'; @NgModule({ declarations: [ AppComponent, LoaderComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule ], providers: [ LoaderService, { provide: HTTP_INTERCEPTORS, useClass: LoaderInterceptorService, multi: true } ], bootstrap: [AppComponent] }) export class AppModule { }
Output:
If you want to use any other loader design, then you just have to make changes in loader.component.css and loader.component.html.
Here are some reference URLs:
– – –
Please give your valuable feedback and if you have any questions or issues about this article, please let me know.
Also, check Form Validation In Angular 9
this is a great implementation, but i am just wondering if i am looking to create a individual loader service for each component without the http interceptor, how should i go about doing it?