Angular show spinner for every HTTP request with very less code changes

@jornare has a good idea in his solution. He’s handling the case for multiple requests. However, the code could be written simpler, without creating new observable and storing requests in memory. The below code also uses RxJS 6 with pipeable operators:

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpInterceptor,
  HttpResponse
} from '@angular/common/http';
import { finalize } from 'rxjs/operators';
import { LoadingService } from '@app/services/loading.service';
import { of } from 'rxjs';

@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
  private totalRequests = 0;

  constructor(private loadingService: LoadingService) { }

  intercept(request: HttpRequest<any>, next: HttpHandler) {
    this.totalRequests++;
    this.loadingService.setLoading(true);

    return next.handle(request).pipe(
      finalize(() => {
        this.totalRequests--;
        if (this.totalRequests === 0) {
          this.loadingService.setLoading(false);
        }
      })
    );
  }
}

Add this interceptor service into your module providers:

@NgModule({
  // ...
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: LoadingInterceptor, multi: true }
  ]
})
export class AppModule { }

Here’s an example of the LoadingService implementation:

@Injectable()
export class LoadingService {
  private isLoading$$ = new BehaviorSubject<boolean>(false);
  isLoading$ = this.isLoading$$.asObservable();
  
  setLoading(isLoading: boolean) {
    this.isLoading$$.next(isLoading);
  }
}

And here’s how you’d use the LoadingService in a component:

@Component({
  selector: 'app-root',
  template: `
    <ng-container *ngIf="loadingService.isLoading$ | async">
      <i class="loading"></i>
    </ng-container>
    <router-outlet></router-outlet>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  constructor(public loadingService: LoadingService) {}
}

Leave a Comment