Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJS - switchMap not emitting value if the input observable is empty array

I have the setup where I query firebase for list of user favourite posts.

Basically, at first I query for user likes and then for each like get the corresponding post - all in one observable sequence.

The problem arises when user dislikes the only left post. In that case (when the likes array becomes empty) nothing is fired from the observable and view is not updated (there is always at least one post present).

On the one hand, this behaviour seems logical and understandable, but on the other hand, I'm not sure how to make final Observable emit even if the input to the switchMap was empty. Maybe should change the operator.

getUserFavourites(userId = ""):Observable<Post[]>
{
  if (!this.userFavourites$) {
    this.userFavourites$ = this.af.database.list('/ranks_by_user/' + userId, {
        query: {
          limitToFirst: 50
        }
      }) //Emits value here (even empty array)
      .switchMap((likes: any[]) => Observable.combineLatest(
        likes.map(like => this.af.database.object("/posts/" + like.$key).first())
      )) //Does not emit new value here if likes array was empty
      .map(p => {
        return p.map(cit => Post.unpack(p));
      }).publishReplay(1).refCount()
  }
  return this.userFavourites$;
}
like image 905
Daniil Andreyevich Baunov Avatar asked Jan 18 '17 15:01

Daniil Andreyevich Baunov


People also ask

How do you know if an observable is empty?

The RxJS isEmpty() operator returns an observable with a Boolean value indicating whether the observable was empty or not. It returns an output as true if the source observable is empty; otherwise, false.

How does switchMap work in RxJS?

RxJS switchMap() operator is a transformation operator that applies a project function on each source value of an Observable, which is later merged in the output Observable, and the value given is the most recent projected Observable.

What does switchMap return?

SwitchMap switches to the most recent observable The SwitchMap operator returns an observable using the interval method. The interval method creates an infinite observable, which emits a sequence of integers spaced by a given time interval.


1 Answers

Solved the problem by adding a condition inside switchMap:

Original - https://github.com/ReactiveX/rxjs/issues/1910

getUserFavourites(userId = ""):Observable<Post[]>
{
  if (!this.userFavourites$) {
    this.userFavourites$ = this.af.database.list('/ranks_by_user/' + userId, {
        query: {
          limitToFirst: 50
        }
      }) //Emits value here (even empty array)
      .switchMap((likes: any[]) => {
      return likes.length === 0 ?
        Observable.of(likes) :
        Observable.combineLatest(
          likes.map(like => this.af.database.object("/citations/" + like.$key))
      )
    }) //Emits either combined observables array or empty array
      .map(p => {
        return p.map(cit => Post.unpack(p));
      }).publishReplay(1).refCount()
  }
  return this.userFavourites$;
}
like image 153
Daniil Andreyevich Baunov Avatar answered Sep 21 '22 17:09

Daniil Andreyevich Baunov