APIに対するHTTP呼び出しのng4-loading-spinner
スピナーを表示しようとしています。
次のリンクの例に基づいてコードを作成しました。
私のAngular 5アプリには複数の複数のモジュールがあります。HTTPインターセプターは「サービス」モジュールにあります。
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;
}
問題は、ApiService
が@angular/http
のHttp
ではなく@angular/common/http
のHttpClient
を使用していたことでした。
したがって、ApiInterceptor
には傍受するものはありません。
reportProgress:trueを忘れます。問題は、「する」という出来事を区別しなければならないということです。さらに、呼び出しを数える必要があるため、インターセプターは
contador: number = 0;
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.contador++;
if (this.contador === 1) {
this.spinner.show();
}
let handleObs: Observable<HttpEvent<any>> = next.handle(req);
handleObs
.catch((err: any) => { //If an error happens, this.contador-- too
this.contador--;
return Observable.throw(err);
})
.do(event => {
if (event instanceof HttpResponse) { //<--only when event is a HttpRespose
this.contador--;
if (this.contador==0)
this.spinner.hide();
}
});
return handleObs;
}
保留中のリクエストがない場合でも、カウンターに問題が発生して二度とゼロに到達しない場合:カウンターを増やすの場合、イベントのタイプをさらに確認する必要がありました。
if (event instanceof HttpResponse) {
this.counter.dec();
} else {
this.counter.inc();
}
それ以外の場合は、HttpResponseの場合もカウンターが増えていました。上記のチェックで、すべてのコンポーネントでカウンターがゼロに戻ります。
また、httpエラー(例:401)が返されてカウンタが減少していることを確認してください。そうしないと、カウンタが再びゼロになることはありません。そうするために:
return next.handle(req).pipe(tap(
(event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
this.counter.dec();
}
},
err => {
if (err instanceof HttpErrorResponse) {
this.counter.dec();
}
}
));
この問題までフォローしているすべての人にとって、ローダーが隠さないように見える残りの問題を除いて、OPのコードは正常に機能しています。その修正は、次のように。catch .doチェーンの後にObservableにsubscribeすることです。
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();
}
})
.subscribe(); /* <---------- ADD THIS */
return handleObs;
この後、コードは正常に機能し、カウンターが0に達するとローダーが非表示になります。上記のすべての回答に感謝します。