shiva
shiva

Reputation: 764

RxJs: How to combine two observable into a new observable with different type

I'm very new to RxJs and NgRx store , I'm want to create an @Effect with combination of two observables (very difficult to explain):

My interfaces looks like:

export interface ProductDetails {
  product: Product;
  productBody: ProductBody;
}

export interface ProductBody{
  id: string;
  body: string;
}

I'm trying to create a new objectproductDetails and set it's properties. properties are product which payload has product and productBody which gets it from productService(id) (It returns observable<productBody>)

This effect should return observable<productDetails>

   @Effect()
  getProductDetails$ = this.actions$
    .ofType(ProductActions.GET_STEP)
    .map(action => action.payload)
    .flatMap(s => {
      let body;
      this.productService.getStepBody(s.id).subscribe(x => body = x);
      return Observable.of({
        step: s,
        productBody: body
      });
    })
    .map(res => this.productActions.getProductDetailsSuccess(res));

this returns:Object {productBody: undefined, product: Object}

I understand why is returning undefined for productBody but not sure how to fix it. I tried using zip, switchMap and etc but no chance!

Upvotes: 4

Views: 1701

Answers (1)

Tyler Jennings
Tyler Jennings

Reputation: 8911

Here is what you can do.

  • You want to flatMap over the original observable to get the payload.id to give it to the getStepBody observable.
  • Then, inside the flatMap, you want to map on the getStepBody observable to return a new value that is a composite object of the payload and the response of the getStepBody.
  • Finally subscribe to get the final result.

It looks something like this:

getProductDetails$ = this.actions$
    .ofType(ProductActions.GET_STEP)
    .map(action => action.payload)
    .flatMap(payload => this.productService.getStepBody(payload.id).map(body => ({step: payload, productBody: body})))
    .subscribe(res => this.productActions.getProductDetailsSuccess(res));  //res is an object of {step: payload, productBody: body}

If you are not wanting to return the whole object into a single function in the subscribe function, you could destructure the values to make them easier to consume separately. To that change the subscribe line to:

.subscribe(({step, body}) => {//do something with each value});

Upvotes: 3

Related Questions