7

I'm kind off new to rxjs, and I've a fairly simple case that I can't work out in angular.

I've a http call to retrieve a group, this group contains a list of "buddy ids", a list of "genre ids" and a "region id".

To get the buddy objects trough the "buddy ids", I have to make a call to an API trough my service ( which return 1 buddy with given id ).

To get my genre objects, I can retrieve them form my store, same for region.

The problem is I can't have a solution worked out with pipes.

this.buddyService.getGroup(groupId).pipe(
    mergeMap((group) => forkJoin(
          mergeMap(() => forkJoin(group.buddyIds.map((id) => this.buddyService.getBuddy(id)))), 
          mergeMap(() => forkJoin(group.genreIds.map((id) => this.store.select(GenreState.genre(id))))),
          switchMap(() => this.store.select(RegionState.region(group.regionId))))
    ), takeUntil(this.destroyed$)
).subscribe(([group, buddies, genres, region]) => {

});

So the first mergeMap will be to get all the results togehter in 1 subscribe, then I've 3 sub calls to get the buddies, genres and the region.

I'd like to have my initial response ( the group ) and the results of the 3 subcalls in 1 subscribe, obviously this solution doesn't work, and I can't seem to get something else to work.

Any help would be appreciated, thanks !

2 Answers 2

5

Seems you have too many inner mergeMaps. Try this

this.buddyService.getGroup(groupId).pipe(
  mergeMap((group) => forkJoin(
    of(group),
    forkJoin(...group.buddyIds.map((id) => this.buddyService.getBuddy(id))), 
    forkJoin(...group.genreIds.map((id) => this.store.select(GenreState.genre(id)))),
    this.store.select(RegionState.region(group.regionId)))
  ),
  takeUntil(this.destroyed$)
)
.subscribe(([group, buddies, genres, region]) => {});

The main issue was that you've combined "constructing" methods that create Observables (like forkJoin) with operators that operate on existing Observables (like switchMap or mergeMap).

Test the difference yourself: switchMap vs forkJoin

I've written this w/o deep testing, so it might not work immediately :)

Sign up to request clarification or add additional context in comments.

6 Comments

I'll try it out later in the evening and respond if it works, thanks though, I'm very new to rxjs so it's a lot :)
do you have any resources outside of the official docs for rxjs, I don't find them that clear
@TanguyB, well, on practical side -- I would highly recommend the rxjs playground I've created. On theoretical side -- I feel your pain, current documentation mostly lacks simplicity and transparency. Try learnrxjs.io -- they have good examples and theres this old book on RxJS 4 that you might get some concepts from. + there are couple of egghead courses on RxJS, though they are behind a paywall.
@TanguyB, I've just googled for some rxjs resources -- and theres a tonn of tutorials and articles on this theme, actually. Though since I see most of them for the first time -- I cant honestly recommend them. Yet, here are two videos that might help you with a start: RxJS Quick Start with Practical Examples and a series of video tuts by RxJS core contributors Ben Lesh and Tracy Lee. Basically just google around, you'll find what fits you best! ;)
@Hi, I tried your solution, it doesn't seel to get in the subscribe part, any clues ?
|
2

This version is a little more verbose, but might be easier to reason about as it is divided into several chunks. Haven't tested it though.

import {combineLatest} from 'rxjs';

...

  const group$ = this.buddyService.getGroup(groupId);
  const buddies$ = group$.pipe(mergeMap(group => combineLatest(group.buddyIds.map((id) => this.buddyService.getBuddy(id))));
  const genres$ = group$.pipe(mergeMap(group => combineLatest(group.genreIds.map((id) => this.store.select(GenreState.genre(id))));
  const region$ = group$.pipe(switchMap(group => this.store.select(RegionState.region(group.regionId)))));

  combineLatest([group$, buddies$, genres$, region$])
    .pipe(takeUntil(this.destroyed$))
    .subscribe(([group, buddies, genres, region]) => {});

6 Comments

I tried your solution, it doesn't seem to hit the subscribe part, any clues ?
So forkJoin assumes that all the Observables completes, but that is probably not the case with the store.select. I have changed the last forkJoin to a combineLatest, that might solve the issue.
Alternatively we could make the store.select complete by changing it to "this.store.select(RegionState.region(group.regionId)).pipe(take(1))".
I changed all the forkJoins in the example to combineLatest now, then it should work. But if what you want is to get just one value, then you should change back to forkJoin, and add the ".pipe(take(1))" after all the observables that does not complete.
yeah the problem was indeed the store.select ( if i do a selectsnapshot on the store in subscribe it works ). I'll try with your latest solution
|

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.