0

Below My code works well.

But, I think combineLatest in other observable ($fromArray)'s operator (map) is weird.

How can I make combineLatest as observable itself?

const item = ["television", "pc", "radio", "camera"];
const fooMarket = webSocket("wss://api.fooMarket.com/websocket/");
const barMarket = webSocket("wss://api.barMarket.com/websocket/");

// market WS unit Stream is like below (emit real-time price change for each Item, but Arbitrary Item Emission)
// {
//   itemName : "televison",
//   price: 980
// }

const fromArray$ = of(...item).pipe(
  map((x) => {
    const fooItem = fooMarket.pipe(
      filter((y) => y.itemName === x),
      map((z) => ({ itemName, price: item.price }))
    );
    const barItem = barMarket.pipe(
      filter((y) => y.itemName === x),
      map((z) => ({ itemName, price: item.price }))
    );

    combineLatest({ [`foo-${x}`]: fooItem, [`var-${x}`]: barItem }).subscribe(
      console.log
    );
    // return combineLatest({ [`foo-${x}`]: fooItem, [`var-${x}`]: barItem }).subscribe; // this way makes fromArray$'s type as 'Subscription' (not 'Observable' type)
  })
);

fromArray$.subscribe();

// result is like below
// {
//   "foo-television": { itemName : "television", price: 980 },
//   "bar-television : { itemName : "television", price: 950 }
// }
// {
//   "foo-pc": { itemName : "pc", price: 110 },
//   "bar-pc : { itemName : "pc", price: 120 }
// }
// ...continuing as Real-time Price Change
reaver lover
  • 624
  • 7
  • 20

1 Answers1

1

Your question is not completely clear to me but I think you want to get rid of nested subscriptions. (Correct me if I'm wrong please)

For that you just need to replace the map operator with mergeMap and return the combineLatest observable from the projection function.

Like this:

const fromArray$ = of(...item).pipe(
  mergeMap((x) => {
    ...

    return combineLatest({ [`foo-${x}`]: fooItem, [`var-${x}`]: barItem })
  })
);

fromArray$.subscribe();

EDIT: Alternative to get array of combineLastest as requested in the comments

As an alternative, if you want to get an array of combineLatest Observables and have the possibility to handle them individually or as a whole, you could extract the mergeMap logic to a function and then map the array of items to an array of combineLastest.

function livePricingFor(itemName: string) {
  const fooItem = fooMarket.pipe(
    filter((item) => item.itemName === itemName),
    map((item) => ({ itemName, price: item.price }))
  );
  const barItem = barMarket.pipe(
    filter((item) => item.itemName === itemName),
    map((item) => ({ itemName, price: item.price }))
  );

  return combineLatest({
    [`foo-${itemName}`]: fooItem,
    [`bar-${itemName}`]: barItem,
  });
}

... 

const items = ["television", "pc", "radio", "camera"];
const itemsLivePricingObservables = items.map(livePricingFor); // Array of combineLastest

Done this, to subscribe to them all, you could use the merge operator

merge(...itemsLivePricingObservables).subscribe()

Or if you just want to subscribe to one of them you access to it via the array index

itemsLivePricingObservables[0].subscribe();

cheers

akotech
  • 1,961
  • 2
  • 4
  • 10
  • can I access each `combineLatest` Observable of `mergeMap`? – reaver lover Jul 24 '22 at 11:08
  • 1
    what you mean by access? If you want to apply operators to all of them, you can do it inside the mergeMap. But if you want to subscribe to each of them independently, then this is not the correct approach. – akotech Jul 24 '22 at 11:12
  • I mean dynamically generate `combineLatest` Observable as variable with loop(*of(...item)*)for this case). Can I declare array for these `combineLatest` and then allocate combineLatest as array elements inside `mergeMap`? – reaver lover Jul 25 '22 at 07:48
  • 1
    @reaverlover I've edited the answer to include the alternative to get an array of combineLatest. I hope it is what you were asking for. cheers – akotech Jul 26 '22 at 09:16