1

I try to find a way to get this scenario working :

  • I have an observable talks$ which emits a list of all talks.
  • A talk have a property personId
  • This property can be mapped to the person using an Observable.
  • I try to map it into a class TalkWithPerson

const test = this.talks$.pipe(
  exhaustMap(talks =>
    talks.map(t => this.getPersonById(t.personId).pipe(map(p => newTalkWithPerson(t, p))))
  ),
);

Currently, this emits 2 observable, each one emitting my TalkWithPerson object. (Observable<Observable<TalkWithPerson>>)

I would like to have an Observable<TalkWithPerson[]> if possible.

I was thinking going the hard way with getting all the people and all the talks and use combineLatest with a project function to match the records but I don't want to load all the persons, it will cause to load a huge list...

Thank you for your help !

StackBlitz : https://stackblitz.com/edit/talks-person

2 Answers 2

2

Try this:

const test = this.talks$.pipe(
    exhaustMap(talks =>
        from(talks)
            .pipe(
                mergeMap(t => this.getPersonById(t.personId).pipe(map(p => newTalkWithPerson(t, p)))),                  
                toArray())
            )
  ),
);
  • Import from as creation method import { from } from "rxjs";
  • Import toArray same as the 'map' pipeable operator
Sign up to request clarification or add additional context in comments.

5 Comments

toArray cause the observable to not emit, certainly because the source is not completed
The toArray here is on the inner observable that is created from 'talks'. By the name 'getPersonById' I assumed it is an observable that completes after one value. Lmk if it doesn't and I will edit my answer.
I change the method getPersonById to get completed after one value and it's working, thanks !
But could you give me a way if getPersonById will not return once? Just for learning :)
If it doesn't complete immediately you should decide on when to collect all the emitted items and transform them to array. It really depends on your case, but here are some options: Take only the first item from 'getPersonById' - You can use take(1) in the pipe before 'map'. Buffer items and emit them after period of time has passed - check the buffer operators
0

Use flatMap operator for this. flatMap will unwrap an Observable<Observable<TalkWithPerson[]>> into Observable<TalkWithPerson[]>

So try doing this:

const test = this.talks$.pipe(
  exhaustMap(talks =>
    talks.flatMap(t => this.getPersonById(t.personId).pipe(map(p => newTalkWithPerson(t, p))))
  ),
);

2 Comments

exhaustMap(talks => : here talks is not an observable so no flatMap and the dot notation for rxjs is dead btw
Can you create a stackbliz if possible?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.