2
votes

I'm using Redux and RxJS Angular (4) implementation to manage state & actions reactivly into my app.

I'm listening to one event (a change on the selected product ID in a product list) so we call it selectedProductId$.

When the related emitter emits a new selectedId value, I want to do a switchMap from this Observable value, along with the latest emitted values from two other Observables (let's say; productDetails$ and productComments$).

So the "triggering change" should be the selectedProductID and we would do a switchMap with latest values of productDetails and productComments.

I tried this :

// subscribed to the 3 observable passed in combineLatest
 fetchProduct$: Observable<any>;
 this.fetchProduct$ = Observable.combineLatest(
       this.selectedProductId$,
       this.productComments$,
       this.productDetails$
 ).switchMap(
       result => Observable.of(
         {
           'uuid': result[0],
           'comments': result[1],
           'details': result[2]
         }
      )
 );

Then I subscribe to this observable and put a break point on the value passed :

this.fetchProductSubscription = this.fetchProduct$.subscribe(result => this.someFn(value));

It works but is called each time one of the three Observables detects state change. I also tried Observable.forkJoin, but from the doc, it waits for the three Observable to emit new value, which make me weird state as I get comments from another Webservice and it can retrieve it when the next product Id is selected.

Observable.merge is also not a solution as it will emit only values one by one on one "channel".

I'm not fully used to reactive programming and maybe I don't clearly see an obvious solution, but right know I would love a hint or some help to solve this problem :( Thanks a lot

2

2 Answers

3
votes

Try withLatestFrom, which works similar to combineLatest() but fires each time the source observable fires. Example (for rxjs 5.5):

this.fetchProduct$ = 
  this.selectedProductId$.pipe(
   withLatestFrom(
       this.productComments$,
       this.productDetails$
   ));

Or for earlier versions:

this.fetchProduct$ = 
  this.selectedProductId$.withLatestFrom(
       this.productComments$,
       this.productDetails$
   );
1
votes

First, let's merge the "extra" observables that you don't want to trigger any changes.

const extras$ = Observable.combineLatest(this.productComments$, this.productDetails$);

Now, we watch for emissions in our "interesting" observable, and just use the latest values from our extras.

cosnt allTogether$ = this.selectedProductId$.withLatestFrom(extras$,
    ([uuid, [comments, details]]) => ({uuid, comments, details}) );

Now feel free to subscribe to allTogether$.