Use RxJs Pipe to reduce Observable to different type
Solution 1
So Chau Tran put me on the right lines. Apparently I needed to switchMap
the Observable to a Recipe[]
and the reduce
operator was then happy to accept a Recipe
as the value. Solution as follows:
this.foodService.getAllReceipes()
.pipe(
switchMap(data => data as Recipe[]), <<== ADDED THIS
reduce((array: ChartData[], value: Recipe) => {
const author = this.createOrFindAuthor(array, value);
author.y += 1;
return array;
}, new Array<ChartData>()),
switchMap(data => this.chartData$ = of(data.sort((a, b) => b.y - a.y)))
)
.subscribe();
Solution 2
After reduce
, try:
switchMap(data => {
this.chartData$ = of(data.sort((a, b) => b.y - a.y));
return this.chartData$;
})
.subscribe()
Comments
-
Simply Ged almost 2 years
I have an
Observable<Recipe[]>
that I want to reduce to an array of a different classChartData[]
to use as a data source for a highcharts graph (column and piechart).I am trying to use the RxJS pipe operator on the
Observable<Recipe[]>
to call the reduce operator on my data but I cannot get it to work? Thereduce
operator does not iterate over them items in myObservable<Recipe[]>
Below is my attempt:this.foodService.getAllReceipes() .pipe( reduce((array: ChartData[], value: Recipe[], i: number) => { const author = this.createOrFindAuthor(array, value[i]); author.y += 1; return array; }, new Array<ChartData>()) ) .subscribe(data => this.chartData$ = of(data.sort((a, b) => b.y - a.y))); }
getAllRecipes()
returns theObservable<Recipe[]>
this.chartData$
isObservable<ChartData[]>
I am trying to reduce this to
ChartData[]
. I have been able to do this in thesubscribe
operator and the graphs display the expected data but I thought I should be able to do it as a pipeable operator? Here is the reduce being done as part of the subscribe:this.foodService.getAllReceipes() .subscribe((data) => { const list = data.reduce((arr: ChartData[], v: Recipe) => { const author = this.createOrFindAuthor(arr, v); author.y += 1; return arr; }, new Array<ChartData>()); this.chartData$ = of(list.sort((a, b) => b.y - a.y)); });
I have tried using the
subscribe
code within the pipeablereduce
but I get compile errors saying that the method expectsRecipe[]
for the value. But if I use the array then I only get the first element from the Observable (or am I just getting the Observable and need to do something with that?)Is this possible or is my thought process wrong about how the pipeable operator should work on the Observable?
For reference here are the models and the createOrFindAuthor function:
export class Recipe { public Title: string; public Author: string; public Source: string; public Page: number; public Link?: string; } export class ChartData { name: string; y: number; } private createOrFindAuthor(array: ChartData[], recipe: Recipe): ChartData { const name = (recipe.Author.length > 0 ? recipe.Author : 'UNKNOWN'); let found = array.find(i => i.name === name); if (!found) { const newData = new ChartData(); newData.name = name; newData.y = 0; array.push(newData); found = newData; } return found; }
-
Simply Ged almost 6 yearsAlthough that improves my code it doesn't solve the problem of getting the
reduce
operator to iterate over all the items in the Observable. -
Simply Ged almost 6 yearsYou put me on the right lines, just needed an additional
switchMap
:-) -
Chau Tran almost 6 yearsYeah my bad, for some reason I thought you'd get the
Recipe[]
inreduce
already. -
kctang almost 6 yearsI just realized you need "Observable<Recipe[]>" instead of "Observable<Recipe>" as input. Sorry! Anyway, I hope the demo can serve as a guide to tweak from. :-)