Angular с RxJS: убедитесь, что конструктор службы, использующий http.get, завершен до вызова метода - PullRequest
0 голосов
/ 27 августа 2018

В Angular 6 у меня есть ConfigService, который требует, чтобы конструктор закончил работать хорошо:

import { HttpClient, HttpHeaders, HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable, Subscribable, Subscription } from "rxjs";

@Injectable()
export class ConfigService {
    public configKeys: any;

    constructor(private http: HttpClient) {
        this.http.get('config/config.json').subscribe(
            data => {
                this.configKeys = data;
            },
            (err: HttpErrorResponse) => {
                console.log (err.message);
            }
        );
    }

    getDocBaseRoute() :string{
        return this.configKeys.docBaseRoute;
    }

    getAuthenticationBaseRoute() :  Subscription {
        return this.configKeys.authenticationBaseRoute;
    }
}

При попытке вызвать метод службы возникает проблема:

this.baseUrl = this.configservice.getAuthenticationBaseRoute();

На самом деле в данный момент configKeys не определено, поэтому return this.configKeys.authenticationBaseRoute; выдает ошибку.

Не могли бы вы помочь мне узнать, как я могу быть уверен, что конструктор завершен до вызова методов службы?

Ответы [ 3 ]

0 голосов
/ 28 августа 2018

Хорошо, я нашел способ сделать это: преобразовать наблюдаемое в обещание, используя toPromise ()

import { HttpClient, HttpHeaders, HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";

@Injectable()
export class ConfigService {
    public configKeys: any;

    constructor(private http: HttpClient) {
    }

    async getGestionDocumentBaseRoute(): Promise<string> {
        await this.initialize();
        return this.configKeys.gestionDocumentBaseRoute;
    }

    private async initialize(): Promise<boolean> {
        if (!this.configKeys) {
            await this.http.get('config/config.json').toPromise()
                .then(
                    data => {
                        this.configKeys = data;
                    }
                )
                .catch(
                    (err: HttpErrorResponse) => {
                        console.log(err.message);
                        return false;
                    }
                );
        }
        return true;
    }

    async getAuthenticationBaseRoute(): Promise<string> {
        await this.initialize();
        return this.configKeys.authenticationBaseRoute;
    }
}
0 голосов
/ 28 августа 2018

Вы должны использовать RxJS повсюду, чтобы это работало должным образом.

import { HttpClient, HttpErrorResponse } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { shareReplay, map } from 'rxjs/operators';

@Injectable()
export class ConfigService {
    private configuration: Observable<any>;

    constructor(private http: HttpClient) { }

    getDocBaseRoute(): Observable<string> {
        return this.getConfiguration().pipe(map(data => data.docBaseRoute));
    }

    getAuthenticationBaseRoute(): Observable<any> {
        return this.getConfiguration().pipe(map(data => data.authenticationBaseRoute));
    }

    private getConfiguration(): Observable<any> {
        if(!this.configuration) {
            this.configuration = this.http.get('config/config.json').pipe(
                catchError((error: HttpErrorResponse) => console.log(err.message)),
                shareReplay()
            );
        }

        return this.configuration;
    }
}

Обратите внимание, что я сохраняю Observable, а не результат в свойстве. Если вы этого не сделаете и вызовете getConfiguration() несколько раз, то из-за синхронизации может произойти несколько HTTP-вызовов. Для этого также важно использовать оператор RxJS shareReplay.

Использование:

this.configservice.getAuthenticationBaseRoute().subscribe(baseRoute => this.baseUrl = baseRoute);
0 голосов
/ 27 августа 2018

У вас нет способа сделать это, что противоречит концепции RxJS.

На мой взгляд, это скорее проблема зачатия, для решения этой проблемы могут быть разные решения:

  1. Определите значение по умолчанию для configKeys, чтобы getAuthenticationBaseRoute никогда не выходил из строя.

  2. Обработайте случай, когда configKeys равен null внутри getAuthenticationBaseRoute, и верните его undefined. Но вы должны также обработать этот случай, когда вы звоните getAuthenticationBaseRoute.

  3. Сделайте так, чтобы компонент / служба / все, что вызывает getAuthenticationBaseRoute, не могло вызвать его до того, как configKeys определено внутри ConfigService.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...