sebba23
sebba23

Reputation: 574

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

Upvotes: 0

Views: 97

Answers (2)

Harun Yilmaz
Harun Yilmaz

Reputation: 8558

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

Upvotes: 1

Seba Cherian
Seba Cherian

Reputation: 1793

You can try this

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

Upvotes: 1

Related Questions