7

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$;
}
3
  • I think that when the likes array it's null should throw a error and that it's stoping the chain you could try to add a catch Commented Jan 18, 2017 at 15:54
  • Thanks for the idea, mate. It will probably work. Actually I will give it a try :) Commented Jan 18, 2017 at 16:03
  • Found a great solution. Check it out. Commented Jan 18, 2017 at 16:17

2 Answers 2

7

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$;
}
Sign up to request clarification or add additional context in comments.

2 Comments

this was a life saver for me!
To summarize, forkJoin([]) in a switchMap would stop the RxJS stream from continuing its processing. Returning of([]) from the switchMap allows processing to continue.
0
.switchMap((likes) => likes.length > 0 ?
   Observable.combineLatest(
    likes.map(like => this.af.database.object("/posts/" + like.$key).first():
   Observable.empty() // if emit empty() then .map() will not run 
 )
 .map(...)

2 Comments

Can you please add a little more explanation around your answer?
For siwtchMap().map() chain. If you return empty Observable (Observable.empty()) inside switchMap, then .map() chain won't be triggered.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.