Angular 2多重订阅

时间:2019-03-26 12:12:33

标签: angular api angular2-services

您好,我正在开发一个应用程序,该应用程序将被部署在带有扫描仪设备的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';

并基于此scanDestination,我应用了一个过滤器来进行不同的调用。 我的问题是此解决方案不起作用?是因为我需要放置三个不同的订阅吗? 我该如何运作?

谢谢

2 个答案:

答案 0 :(得分:1)

您可以尝试

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

答案 1 :(得分:1)

如果要在1个订阅中使用switch/case,则可以在switchMap中使用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值与订阅本身一起传递,以选择在订阅生成值时调用哪个switch/case。因此,第二个subscribe被添加到combineLatest回调中。

import { combineLatest } from 'rxjs';应该这样导入:tap

更新2

正如您在评论中所问的那样,如果您要调用另一个API(我假设它是一个独立的API调用,这意味着它与响应无关),则可以使用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 });

display: flex;

执行/点击:https://www.learnrxjs.io/operators/utility/do.html