Ever faced this?
- You make two or more HTTP requests in Angular
- Multiple loaders show up β and flicker
- Or the loader hides before all calls are done
Letβs fix that! In this article, Iβll walk you through how to build a global, smart HTTP loader using Angular interceptors. Itβll:
β
Show just one loader for any number of API calls
β
Stay visible until all requests finish
β
Make your app feel polished and professional
π§ Whatβs the Problem?
Angular apps often make multiple HTTP calls β maybe to load user data, dashboard stats, and notifications.
But if each call has its own loader logic, the UI becomes a mess:
- Loaders flash on and off
- Users think the app is done loading when it's not
- Code becomes hard to manage
Letβs centralize this using HTTP interceptors and a shared LoaderService.
π§ Step-by-Step Implementation
1οΈβ£ Create the LoaderService
This service will track the number of active requests.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class LoaderService {
private requestCount = 0;
public isLoading$ = new BehaviorSubject<boolean>(false);
show() {
this.requestCount++;
if (this.requestCount === 1) {
this.isLoading$.next(true);
}
}
hide() {
if (this.requestCount > 0) {
this.requestCount--;
}
if (this.requestCount === 0) {
this.isLoading$.next(false);
}
}
reset() {
this.requestCount = 0;
this.isLoading$.next(false);
}
}
2οΈβ£ Create the HTTP Interceptor
This interceptor will automatically call show() and hide().
// loader.interceptor.ts
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { LoaderService } from './loader.service';
@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
constructor(private loaderService: LoaderService) {}
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
this.loaderService.show();
return next.handle(req).pipe(
finalize(() => this.loaderService.hide())
);
}
}
π‘ Key point: The finalize() operator ensures hide() is called whether the request succeeds or fails.
3οΈβ£ Register the Interceptor
Add it to your app module:
// app.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { LoaderInterceptor } from './loader.interceptor';
@NgModule({
// ...
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: LoaderInterceptor,
multi: true,
},
],
})
export class AppModule {}
4οΈβ£ Show the Loader in the UI
You can now show a spinner component anywhere using the isLoading$ observable.
Hereβs a simple example using Angular Material:
<!-- app.component.html -->
<mat-progress-bar
*ngIf="isLoading$ | async"
mode="indeterminate"
color="primary"
></mat-progress-bar>
<router-outlet></router-outlet>
// app.component.ts
import { Component } from '@angular/core';
import { LoaderService } from './loader.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
isLoading$ = this.loaderService.isLoading$;
constructor(private loaderService: LoaderService) {}
}
β Output Demo
When multiple requests fire:
- Youβll see one smooth loader
- It will disappear only when all requests complete
- Works across any part of your app
π Tips and Enhancements
- Delay loader show by 100ms to avoid flashing for fast calls
- Add an exclude list inside the interceptor to skip loader for certain URLs (e.g. logging, analytics)
- Debounce or throttle UI updates if youβre tracking many rapid requests
π§ͺ Bonus: ngx-loading-bar (Optional Lib)
Prefer a library? ngx-loading-bar integrates with Angular interceptors out of the box.
npm install @ngx-loading-bar/core @ngx-loading-bar/http-client
// app.module.ts
import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client';
@NgModule({
imports: [LoadingBarHttpClientModule],
})
export class AppModule {}
Drop this in your layout:
<ngx-loading-bar></ngx-loading-bar>
Boom π₯ Instant loader for all HTTP requests.
π Conclusion
You now have a professional, smart loader system that just works π
Itβs:
- Centralized
- Lightweight
- Easy to maintain
No more copy-pasting loader logic all over your components!
π About Me
Iβm a frontend developer working with Angular, React, and AI-assisted tools. I love writing clean, scalable code and sharing what I learn along the way.
Letβs connect in the comments β and donβt forget to β€οΈ the post if you found it useful!
Would you like me to write the next article in this Angular Pro Tips series on dynamic dashboards with charts?
Top comments (0)