Angular 2 множественная подписка - PullRequest
0 голосов
/ 26 марта 2019

Здравствуйте, я разрабатываю приложение, которое будет развернуто на устройстве Android с подключенным устройством сканера. Я разработал сервисную часть, которая получает отсканированные данные. Моя проблема сейчас заключается в том, что мне приходится различать вызовы 3 api, когда устройство начинает сканирование. Я объясню лучше:

      scannedResult$ = new BehaviorSubject<Api1Response>(null);
      scannedResultApi2$ = new BehaviorSubject<Api2Response>(null);
      scannedResultApi3$ = new BehaviorSubject<Api2Response>(null);

      constructor(
        private scanData: ScanDataService,
        private api: ApiService,
        private scannedDestination: DestinationService
      ) {
        super();
        const scannedResult$ = this.scanData.scanResult$
        .pipe(
          filter(_ => this.scannedDestination.scanDestination === 'Api1'),
          tap(_ => (this.scanning = false)),
          switchMap(scanned=>
            this.api.callApi(Api1Query, {
              DataBar: scanned.DataBar
            })
          )
        )
      .pipe(
      filter(_ => this.scannedDestination.scanDestination === 'Api2'),
      tap(_ => (this.scanning = false)),
      switchMap(scanned =>
        this.api.callApi(Api2Command, {
          DataBar: scanned.DataBar
        })
      )
    )
    .pipe(
      filter(_ => this.scannedDestination.scanDestination === 'Api3'),
      tap(_ => (this.scanning = false)),
      switchMap(scanned =>
        this.api.callApi(Api3Command, {
          DataBar: scanned.DataBar
        })
      )
    )
    .subscribe(result => {
      this.scannedResult$.next(result);
    });
}

Внутри DestinationService Я определил это:

scannedDestination: 'Api1' | 'Api2' | 'Api3';

И на основании этого отсканированного назначения я применяю фильтр для различных вызовов. Моя проблема в том, что это решение не работает? Это потому, что мне нужно поставить три разные подписки? Как я могу заставить это работать?

Спасибо

Ответы [ 2 ]

1 голос
/ 26 марта 2019

Вы можете использовать switch/case в switchMap, если вы хотите сделать это в 1 подписке:

const scannedResult$ = this.scanData.scanResult$
        .pipe(
          tap(_ => (this.scanning = false)),
          switchMap(scanned=> {
            let apiCallType = '';
            switch(this.scannedDestination.scanDestination){
              case 'Api1':{
               apiCallType = Api1Query;
               break;
              },
              case 'Api2':{
               apiCallType = Api2Command;
               break;
              },
              case 'Api3':{
               apiCallType = Api3Command;
               break;
              }
            }
            return combineLatest(
                     this.api.callApi(apiCallType, {
                       DataBar: scanned.DataBar
                     }),
                     of(this.scannedDestination.scanDestination)
                   )
          })
        )
.subscribe(([result, apiType]) => {

       switch(apiType){
              case 'Api1':{
               this.scannedResult$.next(result);
               break;
              },
              case 'Api2':{
               this.scannedResultApi2$.next(result);
               break;
              },
              case 'Api3':{
               this.scannedResultApi3$.next(result);
               break;
              }
            }

});

Редактировать Примечание: Я добавил combineLatest для прохождения apiCallType значение с самой подпиской, чтобы выбрать, какой BehaviorSubject вызывать, когда подписка генерирует значение.Поэтому к обратному вызову subscribe добавляется вторая switch/case.

combineLatest следует импортировать следующим образом: import { combineLatest } from 'rxjs';

Обновление 2

Как вы спросили в комментариях, если вы хотите вызвать другой API (я предполагаю, что это независимый вызов API, то есть он не имеет ничего общего с ответом), вы можете использовать tap из rxjs

       const scannedResult$ = this.scanData.scanResult$
        .pipe(
          tap(_ => (this.scanning = false)),
          switchMap(scanned=> {
            let apiCallType = '';

            let is2or3 = false; // flag to check if Api2Command or Api3Command

            switch(this.scannedDestination.scanDestination){
              case 'Api1':{
               apiCallType = Api1Query;
               break;
              },
              case 'Api2':{
               apiCallType = Api2Command;
               is2or3 = true;
               break;
              },
              case 'Api3':{
               apiCallType = Api3Command;
               is2or3 = true;
               break;
              }
            }


             let apiToCall = this.api.callApi(apiCallType, {
                       DataBar: scanned.DataBar
                     });

            if(is2or3){
                apiToCall = apiToCall.pipe(
                    tap(() => {
                         // do the other API call here.
                         // this.anotherApiCall();
                    })
                )
            }

            return combineLatest(
                     apiToCall,
                     of(this.scannedDestination.scanDestination)
                   )
          })
        )
       .subscribe(([result, apiType]) => {

           // same as above

        });

do / tap: https://www.learnrxjs.io/operators/utility/do.html

1 голос
/ 26 марта 2019

Вы можете попробовать это

 const scannedResult$ = this.scanData.scanResult$
        .pipe(
          filter(_ => ),
          tap(_ => (this.scanning = false)),
          switchMap(scanned=>
            this.api.callApi(this.scannedDestination.scanDestination === 'Api1'? Api1Query: (this.scannedDestination.scanDestination === 'Api2'? Api2Command : Api3Command), {
              DataBar: scanned.DataBar
            })
          ).subscribe(result => {
      this.scannedResult$.next(result);
    });
...