wake-up-neo.com

Angular HTTP-Interceptor - Zeigt den Spinner in einer Multi-Modul-App an

Ich versuche, den ng4-loading-spinner-Spinner für HTTP-Aufrufe anzuzeigen, die an meine API gerichtet sind.

Ich habe meinen Code auf den Beispielen in den folgenden Links aufgebaut:

Meine Angular 5-App verfügt über mehrere mehrere Module. Der HTTP-Interceptor befindet sich im Modul "Services". 

Ich glaube, ich habe ein Problem mit der Abhängigkeit von Abhängigkeiten, da der Code-HTTP-Interceptor-Code nicht ausgeführt wird, wenn ich meinen Code mit Chrome Dev Tools debugge.

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;
}
5

Das Problem war, dass ApiService die Http von @angular/http anstelle von HttpClient von @angular/common/http verwendete.

Die ApiInterceptor hat also nichts zu fangen.

2

reportProgress: true vergessen. Das Problem ist, dass wir das Ereignis "do" diskriminieren müssen. Darüber hinaus müssen wir die Anrufe zählen, so dass der Interceptor so sein muss

contador: number = 0;

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.contador++;
        if (this.condator==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
Eliseo

Für alle, die dieses Problem verfolgen, funktioniert der Code des OP jetzt gut, mit Ausnahme des verbleibenden Problems, das der Loader nicht zu verbergen scheint. Der Fix dazu ist subscribe für das Observable, nach der .catch .do -Kette, so

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;

Danach sollte der Code einwandfrei funktionieren und der Loader wird ausgeblendet, wenn der Zähler 0 erreicht hat. Vielen Dank an alle obigen Antworten für ihren Beitrag!

0
Geiv Tomço