0

I have now this piece of code to filter an observable.

listings$: Observable<Listing[]>;

this.listings$ = this.firestore
      .getListings()
      .pipe(map(listings => listings.filter(listing => listing.promoted === true)));

Which works fine, but I want to make full use of rxjs instead of using the filter on the array.

The this.firestore.getListings() function returns Observable<Listing[]>, and this.listings$ must be Observable<Listing[]> as well.

I tried different approaches, and struggling with this for a while. Maybe you can help me. I'm still "fresh" to angular and rxjs.

this.listings$ = this.firestore.getListings().pipe(
      mergeMap(listings => listings),
      filter(listing => listing.promoted === true)
    );

Type Observable<Listing> is not assignable to type Observable<Listing[]>.

I might be doing something wrong with the mergeMap operator, or even it is not correct operator to use in this case.

I tried to adjust the code from this post. The flatMap operator seem to be changed to mergeMap. But it's still not working.

Rafff
  • 1,510
  • 3
  • 19
  • 38
  • 3
    Using rxjs map and array filter is absolutely a proper way of doing it. Don't go out of your way to change it. – Ingo Bürk Jun 13 '18 at 18:58
  • It looks like the error is caused by the type given to `this.listings$`. Outside of the code shown, you must adjust the code to match an observable stream of individual listing objects. I guess that form is more convenient for your view? –  Jun 13 '18 at 20:29
  • @eric99 I didn't add this part of code in my post. But however it is `listings$: Observable;` – Rafff Jun 13 '18 at 22:28
  • Thanks for that info. So why exactly are you trying to flatten the observable? –  Jun 14 '18 at 01:49

1 Answers1

0

Well, this depends on how you want to use the this.listings$ Observable. Using mergeMap(listings => listings) is correct and it turns Observable<Listing[]> into Observable<Listing> but you said you want to use RxJS filter() operator and you want to have Observable<Listing[]> at the end anyway.

One way could be using take(1) and toArray() operators. toArray() will accumulate all emissions from its source into a single array and when the source competes it emits the array.

this.listings$ = this.firestore.getListings().pipe(
  take(1),
  mergeMap(listings => listings),
  filter(listing => listing.promoted === true),
  toArray(),
);

Note that this listings$ Observable will emit just once and won't react to any subsequent emissions from this.firestore.getListings().

Personally, I'd actually use what you had pipe(map(listings => listings.filter(...))) because this is just easier to use.

martin
  • 93,354
  • 25
  • 191
  • 226
  • Thanks. `this.listings$` is `Observable` so I can subscribe to it and get listings displayed over time as they are added, so `take(1)` is not what I want. I will mark your answer as accepted because you actually covered more than I expected someone would answer. – Rafff Jun 13 '18 at 22:43