0
votes

I am using the NGRX platform in an angular 4 project. I'm using RXJS +5.

On init of a component, I am selecting an array of objects from my store. I want this observable to emit a single array every time data changes in my store.

I am unpacking the array just fine, but packaging the stream of observables back into a single array that emits once is causing me trouble.

I would like to do the following, but this never emits a value because the subscription never completes. To my knowledge, toArray only emits on completion.

 this.addedProducts$ = this._store.select(s=>s.order.selectedProducts)
      .flatMap(prods=>prods) //emits an observable for each product in store
      .map(prod=>prod._id) //returns the id for each product
      .toArray(); // I would like this to be an Observable<string[]>

Instead, I have done something like this:

this.addedProducts$ = this._store.select(s=>s.order.selectedProducts)
  .flatMap(prods=>prods)
  .map(prod=>prod._id)
  .scan((acc, value) => {
    acc.push(value);
    return acc;
  }, [])

But this emits an new array every single iteration of adding an _id to the array. I would like this observable to emit a single array with all the values in it.

How can I achieve this?

2

2 Answers

0
votes

This solution doesn't sit well with me, but it does accomplish what I was looking for. I'm open to hearing different approaches.

this.addedProducts$ = this._store.select(s=>s.order.selectedProducts)
  .map(prods=>{return prods.map((prod)=>prod._id)}); 
0
votes

I think there's a misunderstanding between values over time and current values.

Please let me know, but I think this solution is enough:

this.addedProducts$ = this
  ._store
  .select(s=>s.order.selectedProducts)
  .map(prods =>
    prods.map(prod => prod._id)
  );

The first map is the one from Observable, the second one is just the javascript map that you can use on any array.

So in the end, everytime s.order.selectedProducts changes, you'll get a new array containing all the ids of those products.


That said, you might want to use a selector instead of doing that everywhere in your app:

// in some selector file, for example `products.selectors.ts`
const getSelectedProductsIds => state => state.order.selectedProducts.map(prod => prod._id);

// in every component, effect, whatever where you need to access the selected products IDs
this.addedProducts$ = this._store.select(getSelectedProductsIds);