Home > database >  RxJS use combined emissions as they come
RxJS use combined emissions as they come

Time:06-27

I have an Angular component which needs data from three separate sources, call them s1$, s2$ and s3$. These are, in fact, API calls.

I'm creating a combined value called pageData$, essentialy an object which will hold all three values for the template.

I also want the data displayed as it comes instead of waiting for all requests to complete.

I tried the mergeMap, but realized that this won't work because every nested Observable needs to emit at least once in order for the mapped result to emit. Since these three sources are in fact HTTP requests, this essentially means I'm getting a forkJoin-like behavior.

So, I tried with combineLatest, but it still behaves the same. Here's the code:

constructor(route: ActivatedRoute) {
    // Attempt with mergeMaps:
    this.pageData$ = route.params.pipe( // I get some Id from route parameters
        switchMap(params => s1$.pipe(
            mergeMap(s1 => s2$.pipe(
                mergeMap(s2 => s3$.pipe(
                    map(s3 => {
                        return {
                            data1: s1,
                            data2: s2,
                            data3: s3
                        };
                    })
                ))
            ))
        ))
    );

    // Attempt with combineLatest:
    this.pageData$ = route.params.pipe(
        switchMap(params => this.getPageData$(params['id']))
    );
}

private getPageData$(eventId: string): Observable<EventGroupPageData> {
    return combineLatest([
        s1$,
        s2$,
        s3$
    ]).pipe(
        map(([s1, s2, s3]) => {
            return {
                data1: s1,
                data2: s2,
                data3: s3
            };
        })
    );
}

In template, I'm using an async pipe to unpack the values and render the UI:

<div *ngIf="pageData$ | async as pageData"> render... </div>

Now, I'd like to be able to render each of the three element as soon as that particular piece of data comes from the API, which I can't seem to achieve.

Any ideas?

CodePudding user response:

I think you can use combineLatest, but you need to start each observable with start value, for example it can be a startWith operator, there is an example for you: Stackblitz

  • Related