I am getting a little overwhelmed with combining data streams using declarative RxJS and I haven't been able to figure this one out.
I have two data streams like so:
seriesCards$ = this.http.get<SeriesCard[]>(this.seriesCardsUrl)
.pipe(
shareReplay(1),
catchError(CardsService.handleError)
);
and,
allWatchCards$ = this.http.get<AllWatchCards[]>(this.watchCardsUrl)
.pipe(
shareReplay(1),
catchError(CardsService.handleError)
);
As you can see, each one returns a different object array. I have a requirement in my app that now I need to combine them to return them all together based on a certain criteria for each one.
Each object has a field called category
and that's the one I want to filter on for both.
Ideally I want my service
to combine both the data streams and then my page/component to do the filtering and return each object from both object arrays based on that filter.
My service.ts
:
watchCardWithSeriesCardsForDevotionals$ = combineLatest([
this.allWatchCards$,
this.seriesCards$
]).pipe(
mergeMap(([watchCards, seriesCards]) =>
merge(watchCards, seriesCards),
));
My component.ts
displayBothCards$ = this.cardService.watchCardWithSeriesCardsForDevotionals$
.pipe(
map(bothCards => bothCards) <!-- This is where I want to filter but it defaults to only the one objects field? -->
);
For a reason I am not sure of, the map(bothCards => bothCards)
is flattened to an object instead of an array of those objects so.
An example from a single data stream that I have that I am trying to do with two data streams:
displaySomething$ = this.cardService.allWatchCards$
.pipe(
map(somethingCards => somethingCards.filter(somethingCard => somethingCard.category === 'something')
.sort(sortByDate))
);
Any help and guidance would be appreciated!
CodePudding user response:
You can use forkJoin
:
Service
watchCardWithSeriesCardsForDevotionals$ = forkJoin({
watchCards: this.allWatchCards$,
seriesCards: this.seriesCards$
});
Component
displayBothCards$ = this.cardService.watchCardWithSeriesCardsForDevotionals$
.pipe(
tap(({ watchCards, seriesCards }) => {
console.log(watchCards);
console.log(seriesCards);
}),
map(({ watchCards, seriesCards }) => {
const filteredWatchCards = watchCards.filter((watchCard) => watchCard.category === 'devotional');
const filteredSeriesCards = seriesCards.filter((seriesCard) => seriesCard.category === 'devotional');
return {
myFilterWatchCards: filteredWatchCards as SeriesCards[]
myFilterSeriesCards: filteredSeriesCards as AllWatchCards[]
};
})
);
<ng-container *ngIf="displayBothCards$ | async as bothCards">
<div *ngFor="let watch of bothCards.myFilterWatchCards">
<!-- watch.something -->
</div>
<div *ngFor="let serie of bothCards.myFilterSeriesCards">
<!-- serie.something -->
</div>
</ng-container>
You can read more about it here
CodePudding user response:
It's because you are using the wrong operators. Try this instead:
watchCardWithSeriesCardsForDevotionals$ = combineLatest([
this.allWatchCards$,
this.seriesCards$
]).pipe(
map(([watchCards, seriesCards]) => [...watchCards, ...seriesCards])
);
BTW, the reason your array is flattened is because of the mergeMap
.