'Angular loading interceptor

How to avoid multiple loading in angular loading interceptor In angular each http call loading spinner and tried implement only one loading for initial page loading. How to solve this



Solution 1:[1]

You are working on an existing Angular application.

The application makes HTTP calls to a REST API from lot of various components.

You want to show a custom spinner for every HTTP request. Since this is an existing application, there are lot of places where calls to REST API are made. And changing code one by one at every places is not a feasible option.

So, you would like to implement an abstract solution which would solve this problem.

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(res => {
        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) {}
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ARANYA MUKHERJEE