我正在尝试显示ng4-loading-spinner
微调器,以便对我的API进行HTTP调用。
我的代码基于以下链接中的示例:
我的Angular 5应用程序有多个多个模块。 HTTP拦截器位于“服务”模块中。
我认为我遇到了依赖注入问题,因为当我使用Chrome Dev Tools调试代码时,代码HTTP拦截器代码无法执行。
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;
}
答案 0 :(得分:3)
问题是ApiService
使用Http
中的@angular/http
代替HttpClient
中的@angular/common/http
。
所以ApiInterceptor
无法拦截。
答案 1 :(得分:2)
忘记reportProgress:是的。问题是我们必须区分“做”的事件。而且,我们必须对调用进行计数,因此拦截器必须像
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;
}
答案 2 :(得分:0)
对于处理此问题的每个人,OP的代码现在都可以正常工作,除了加载程序似乎没有隐藏的其余问题。解决方法是,在 .catch .do 链之后,订阅到Observable,就像这样:
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时,加载程序将隐藏。还要感谢上述所有答案!
答案 3 :(得分:0)
对于那些计数器有问题的人,即使没有待处理的请求也永远不会再达到零: 增加计数器时,我不得不额外检查事件的类型:
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();
}
}
));