Reputation: 23
Unable to find a solution to my problem, I ask my question here.
I am retrieving a list of object from my database. Each fruit contains these values : Id, Name, Image, Code and Color.
I would like to display a title for each fruit color.
In my example, I'm getting 2 red fruits and 1 blue fruit. So I would like to get a title "RED" with the 2 red fruits below, and a title "BLUE" with the blue fruit below.
This is what I managed to do :
<div class="col-md-10 offset-md-1 row d-flex justify-content-center after-loop">
<div *ngFor="let fruit of fruits$;">
<div *ngIf="fruit.color == 'red'">
<h3 style="color:#fff"><span style="color:#ea4848">COLOR</span> - Red</h3>
<div *ngIf="active">
<app-fruit [name]="fruit.name" [image]="fruit.image" [code]="fruit.code"
[color]="fruit.color"></app-fruit>
</div>
</div>
</div>
</div>
If the fruit is red, it will print a title above the fruit card. I'm more looking for a "global" title.
Thanks for you help.
Upvotes: 0
Views: 883
Reputation: 8269
I suggest grouping your array with reduce
in accordance to their colors first and get instance on your colors array for us to be able to loop over in the grouped fruits
Have created a Stackblitz Demo for your reference
Component
// Group the fruits by their colors
this.groupedFruits = this.fruits
.reduce((box, fruit) => {
box[fruit.color] = box[fruit.color] ? [ ...box[fruit.color], fruit ] : [ fruit ];
return box;
}, {});
// Grab all the color keys inside your groupedFruits array
this.colors = Object.keys(this.groupedFruits);
Your groupedFruits
's data will then be like this when grouped:
{
red: [{ name: 'apple' }, { name: 'strawberry'}],
yellow: [{ name: 'mango' }],
...and so on
}
Template
<ul *ngFor="let color of colors">
// Color Name with count of how many fruits under that color
<h4 class="ml-0">
{{ color }}
<span class="badge badge-secondary">{{ groupedFruits[color].length }}</span>
</h4>
// loop the fruits according to their color
<li *ngFor="let fruit of groupedFruits[color]">{{ fruit.name }}</li>
</ul>
Upvotes: 1
Reputation: 71941
You'd first have to categorize them in your source data:
This is some custom code, because I can't see your actual data retrieving implementation:
If you have something like this in your component code:
readonly fruits$: Observable<Fruit[]> = this.getFruits().pipe(
shareReplay({ refCount: true, bufferSize: 1 })
);
readonly fruitCats$: Observable<{color: string, fruits: Fruit[]}[]> = this.fruits$.pipe(
map((fruits) => fruits.reduce((cats, fruit) => {
const cat = cats.find(({ color }) => fruit.color === color);
cat ? cat.fruits.push(fruit) : cats.push({ color: fruit.color, fruits: [ fruit ] });
return cats;
}, []),
shareReplay({ refCount: true, bufferSize: 1 })
);
Then you can do the following in your template:
<div class="col-md-10 offset-md-1 row d-flex justify-content-center after-loop">
<div *ngFor="let fruitCat of fruitCats$ | async">
<div *ngIf="fruitCat.color == 'red'">
<h3 style="color:#fff"><span style="color:#ea4848">COLOR</span> - Red</h3>
</div>
<div *ngFor="let fruit of fruitCat.fruits">
<app-fruit [name]="fruit.name" [image]="fruit.image"
[code]="fruit.code" [color]="fruit.color"></app-fruit>
</div>
</div>
</div>
Another option would be to write a custom pipe, to categorize your array by a certain property, but I'll leave that up to you to figure out
Upvotes: 0