Angular 7 / Rxjs: наблюдаемые цепочки и вложения - PullRequest
1 голос
/ 22 апреля 2019

У меня есть набор данных транзакций, который я хотел бы дополнить дополнительными данными, такими как обменный курс на указанную дату, и опубликовать их прямо в моем API. Но я получаю только свои оригинальные транзакции без каких-либо изменений, и я все еще новичок в Angular и Rxjs. Так что я мог бы помочь с операторами.

У меня есть кнопка, которая вызывает несколько API из функции:

// component.ts
public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => this.depositApi.enrichAndSaveDeposit(x));
        }
      );
  }

Получить все необработанные транзакции из локальных API, у которых есть даты. (Это работает)

// depositApiService
public getAllDeposits(): Observable<DepositModel[]> {
    return this.http.get<DepositModel[]>(AppConfig.localJsonServerUrl + AppConfig.api.deposits)
      .pipe(
        catchError(this.handleError('getAllDeposits', null))
      );
  }

Здесь я вызываю внешний API, чтобы получить обменный курс на данную дату, а затем делаю некоторые вычисления и отправляю его обратно в локальный API.

Но он никогда не попадает в часть mergeMap.

// depositApiService
public enrichAndSaveDeposit(deposit: DepositModel): Observable<DepositModel> {
    return this.apiService.getHistoricEurRate(deposit.date)
      .pipe(
        mergeMap(data => {
          deposit.historicExchangeRate = data.rates.USD;
          deposit.exchangeRate = deposit.sellAmount / deposit.buyAmount;
          deposit.sellAmountInUsd = deposit.sellAmount * data.rates.USD;
          deposit.exchangeRateInUsd = deposit.exchangeRate * data.rates.USD;
          return this.saveLocalDeposit(deposit);
        }), catchError(this.handleError('enrichAndSaveLocalDeposit', deposit))
      );
  }

Здесь называется внешний API (это работает).

// apiService
public getRemoteExchangeRates(): Observable<ExchangeRateModel> {
    return this.http.get<ExchangeRateModel>(AppConfig.exchangeRateApi + '/latest')
      .pipe(
        catchError(this.handleError('getRemoteExchangeRates', null))
      );
  }

Это сообщение для местного API. (Никогда не доходит до этой точки)

// depositApiService
private saveLocalDeposit(deposit: DepositModel): Observable<DepositModel> {
    return this.http.post<DepositModel>
      (
        AppConfig.localJsonServerUrl + AppConfig.api.deposits,
        deposit,
        { headers: new HttpHeaders().set('Accept', 'application/json') }
      )
      .pipe(
        catchError(this.handleError('saveLocalDeposit', deposit))
      );
  }

Ответы [ 2 ]

2 голосов
/ 22 апреля 2019

вот ответ, который я дал на аналогичный вопрос, в котором описывается, как вы можете сделать это , как построить один объект из 2 http-запросов в угловом формате, без добавления другого значения

ВКроме того, я хочу предоставить вам совет о RxJS, который, по моему мнению, в настоящее время является частью проблемы.Давайте посмотрим на ваш код, как показано ниже.

public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => this.depositApi.enrichAndSaveDeposit(x));
        }
      );
  }

Этот код подписывается на Observable getAllDeposits, а затем говорит, когда он возвращается со значением, сопоставьте это значение с помощью enrichAndSaveDeposit.Однако ваш код для enrichAndSaveDeposit также является Observable, поэтому, как написано выше, он никогда не будет вызван, поскольку на него никогда не подписываются.Ниже я написал кое-что, что исправит этот конкретный случай.

public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => {
            this.depositApi.enrichAndSaveDeposit(x)
              .subscribe( // this is the subscribe that is needed to make the second part of the chain work
                enrichedResult => {
                  // do something with the enrichedResult here
                }
              );
          };
        }
      );
  }

Надеюсь, это поможет.

1 голос
/ 22 апреля 2019

Проблема в том, что вы никогда не подписываетесь на Observable, возвращаемый с enrichAndSaveDeposit, поэтому http POST никогда не создается.

Было бы достаточно подписать и затем предоставить функцию наблюдателя, даже пустую.

public click() {
    this.deposits = this.depositApi.getAllDeposits()
      .subscribe(
        result => {
          result.map(x => this.depositApi.enrichAndSaveDeposit(x).subscribe(() => {}));
        }
      );
  }

Методы HttpClient Angular (get, post, ... и т. Д.) Возвращают холодные Observables, что означает, что они запускаются только после подписки. Это важно по двум причинам:

  • HTTP-запрос не будет выполнен, если вы не подпишетесь на Observable, возвращаемый этим методом HttpClient.
  • Для каждой Подписки на метод HttpClient будет сделан один запрос.

Чтение следующего поможет вам понять разницу между горячими и холодными наблюдаемыми:

https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html https://medium.com/@benlesh/hot-vs-cold-observables-f8094ed53339

...