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)