I'm trying to display the ng4-loading-spinner
spinner for HTTP calls made to my API.
I based my code on the examples in the following links:
- https://angular.io/guide/http#intercepting-all-requests-or-responses
- Angular4: Using HttpClient's interceptor to setup a spinner
My Angular 5 app has multiple multiple modules. The HTTP interceptor is in the "services" module.
I think I'm having a dependency injection problem because the code HTTP interceptor code doesn't get executed when I debug my code with Chrome Dev Tools.
api-interceptor.ts
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch'
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
HttpResponse
} from '@angular/common/http';
import { Ng4LoadingSpinnerService } from 'ng4-loading-spinner';
@Injectable()
export class ApiInterceptor implements HttpInterceptor {
private count: number = 0;
constructor(private spinner: Ng4LoadingSpinnerService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.count++;
if (this.count == 1) this.spinner.show();
let handleObs: Observable<HttpEvent<any>> = next.handle(req);
handleObs
.catch((err: any) => {
this.count--;
return Observable.throw(err);
})
.do(event => {
if (event instanceof HttpResponse) {
this.count--;
if (this.count == 0) this.spinner.hide();
}
});
return handleObs;
}
}
api.service.ts
import { Injectable, Inject } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { TokenService } from './token.service';
@Injectable()
export class ApiService {
constructor(
private http: Http,
private session: TokenService,
@Inject('BASE_URL') private baseUrl) { }
get(entityRoute: string): Observable<Response> {
let apiRoute = this.getApiRoute(entityRoute);
let options = this.generateRequestOptions();
return this.http.get(apiRoute, options);
}
post<T>(entityRoute: string, entity: T): Observable<Response> {
let apiRoute = this.getApiRoute(entityRoute);
let options = this.generateRequestOptions();
return this.http.post(apiRoute, entity, options);
}
put<T>(entityRoute: string, entity: T): Observable<Response> {
let apiRoute = this.getApiRoute(entityRoute);
let options = this.generateRequestOptions();
return this.http.post(apiRoute, entity, options);
}
private getApiRoute(entityRoute: string): string {
return `${this.baseUrl}api/${entityRoute}`;
}
private generateRequestOptions(): RequestOptions {
let headersObj = null;
let accessToken = this.session.getAccessToken();
if (accessToken) {
headersObj = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
};
} else {
headersObj = {
'Content-Type': 'application/json'
};
}
let headers = new Headers(headersObj);
return new RequestOptions({ headers: headers });
}
}
services.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpModule } from '@angular/http';
import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
import {
ApiInterceptor,
ApiService,
TokenService
} from './index';
@NgModule({
imports: [
CommonModule,
HttpModule,
Ng4LoadingSpinnerModule
],
providers: [
ApiInterceptor,
ApiService,
TokenService
]
})
export class ServicesModule { }
export * from './index';
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { Ng4LoadingSpinnerModule } from 'ng4-loading-spinner';
import { BootstrapModule } from './bootstrap/bootstrap.module';
import { ServicesModule, ApiInterceptor } from './services/services.module';
import { AppComponent } from './app-component';
@NgModule({
bootstrap: [ AppComponent ],
imports: [
BrowserModule,
Ng4LoadingSpinnerModule.forRoot(),
BootstrapModule,
ServicesModule
],
providers: [
{
provide: 'BASE_URL',
useFactory: getBaseUrl
},
{
provide: HTTP_INTERCEPTORS,
useClass: ApiInterceptor,
multi: true,
}
]
})
export class AppModule {
}
export function getBaseUrl(): string {
return document.getElementsByTagName('base')[0].href;
}
The issue was the
ApiService
was using theHttp
from@angular/http
instead ofHttpClient
from@angular/common/http
.So the
ApiInterceptor
has nothing to intercept.For everyone following up to this issue, the OP's code now is working fine, except for the remaining issue that the loader doesn't seem to hide. The fix to that is to subscribe to the Observable, after the .catch .do chain, like so:
After this, the code should be working fine, and the loader will hide when the counter reaches 0. Thanks to all the above answers for their contribution as well!
forget reportProgress:true. The problem is that we have to discriminate the event of "do". Moreover, we must take a count of the calls, so the interceptor must be like