Search code examples
angularapiangular2-services

Angular 2 multiple subscription


Hello I'm developing an app that is gonna be deployed on an android device with a scanner device attached. I have developed the service part that gets the scanned data. My problem now is that I have to differenciate 3 api calls when the device start scanning. I'll explain myself better:

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

Inside DestinationService I have defined this:

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

And based on this scannedDestination I apply a filter to make different calls. My problem is that this solution doesn't work? Is it because I need to put three different subscriptions? How can I make it work?

Thank you


Solution

  • You can use switch/case in switchMap if you want to do it in 1 subscription:

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

    Edit Note: I added combineLatest to pass apiCallType value with the subscription itself to choose which BehaviorSubject to invoke when subscription generates a value. Therefore, a second switch/case is added to the subscribe callback.

    combineLatest should be imported like this: import { combineLatest } from 'rxjs';

    Update 2

    As you asked in the comments, if you want to call another API (I assume it is an independent API call meaning it has nothing to do with the response) you can use tap from 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