Issue
I have the following code that assembles items to display in a NavBar.
For some items, it calls an API to fetch extra info and adds that information to the subtitle
field.
I would like to recombine this into an Observable<NavItem[]>
so it can be rendered using an Async Pipe.
Currently it logs each NavItem
before I call ops.toArray()
. But the log call after ops.toArray()
never returns...
Is there a better RXJS way to recombine these items into a Observable<NavItem[]>
?
import * as ops from 'rxjs/operators';
navItem$: Observable<NavItem[]> = null
this.navItem$ = this.store.pipe(
select(fromRoute.selectLastUrls),
ops.map((d) => {
// Initial construction of NavItems
}),
ops.tap((i) => console.log(i)), // Prints an array of 5 NavItems as expected
ops.mergeAll(),
ops.mergeMap((i) =>
iif(
() => i.listItem,
// Call the API for some list items (To add subtitle detail)
this.backendService.find({ title: [i.title] }).pipe(
ops.map((found) => ({...i, subtitle: found.items[0].info,})),),
of(i),
),
),
ops.tap((i) => console.log(i)), // This expected 1 NavItem per log line (with data appended from the API calls)
ops.toArray(),
ops.tap((i) => console.log(i)) // This line never logs
);
Solution
in your case toArray
waits for the whole stream to complete, and then it would gather all of the elements as one single array.
to apply this logic only to group instead, you will have to put operators on one level deeper. like this:
this.navItem$ = this.store.pipe(
select(fromRoute.selectLastUrls),
ops.map((d) => {
// Initial construction of NavItems
}),
ops.tap((i) => console.log(i)), // Prints an array of 5 NavItems as expected
ops.switchMap(arr => from(arr).pipe(
ops.mergeMap((i) =>
iif(
() => i.listItem,
// Call the API for some list items (To add subtitle detail)
this.backendService.find({ title: [i.title] }).pipe(
ops.map((found) => ({...i, subtitle: found.items[0].info,})),),
of(i),
),
),
ops.tap((i) => console.log(i)), // This expected 1 NavItem per log line (with data appended from the API calls)
ops.toArray(),
))
ops.tap((i) => console.log(i)) // This line will log arrays now
);
I would also mention that it is not recommended to import * as ops from 'rxjs/operators';
as this way all of the oprerators will get into the bundle. If you just import every operator independently then all of the unused ones could be tree shaked away and the bundle should be smaller as a result
Answered By - Andrei
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.