DEV Community

Cover image for πŸ”„ Smart HTTP Loader in Angular Using Interceptors – Show One Loader for All API Calls
Suliman Munawar khan
Suliman Munawar khan

Posted on

πŸ”„ Smart HTTP Loader in Angular Using Interceptors – Show One Loader for All API Calls

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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())
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ 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 {}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode
// 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) {}
}
Enter fullscreen mode Exit fullscreen mode

βœ… 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
Enter fullscreen mode Exit fullscreen mode
// app.module.ts
import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client';

@NgModule({
  imports: [LoadingBarHttpClientModule],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Drop this in your layout:

<ngx-loading-bar></ngx-loading-bar>
Enter fullscreen mode Exit fullscreen mode

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)