I'm using multi select checkbox with angular material chip. I have array objects with name and id, name is supposed to be displayed if user select options and id must be sent to backend. When I assign [value]="topping.id"
, its showing selected id instead of name. How I can show name in UI when user select option and keep id in formControl
? I have added demo link here.
Image 1: Current result
Image 2: Expected result
app.component.html
<mat-form-field>
<mat-label>Toppings</mat-label>
<mat-select [formControl]="toppingsControl" multiple>
<mat-select-trigger>
<mat-chip-list>
<mat-chip
*ngFor="let topping of toppingsControl.value"
[removable]="true"
(removed)="onToppingRemoved(topping)">
{{ topping }}
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-list>
</mat-select-trigger>
<mat-option *ngFor="let topping of toppingList" [value]="topping.id">
{{topping.name}}
</mat-option>
</mat-select>
app.component.ts
toppingsControl = new FormControl([]);
toppingList: any[] = [
{ id: 1, name: 'Extra cheese' },
{ id: 2, name: 'Mushroom' },
{ id: 3, name: 'Onion' },
{ id: 4, name: 'Sausage' }
];
onToppingRemoved(topping: string) {
const toppings = this.toppingsControl.value as string[];
this.removeFirst(toppings, topping);
this.toppingsControl.setValue(toppings); // To trigger change detection
}
private removeFirst<T>(array: T[], toRemove: T): void {
const index = array.indexOf(toRemove);
if (index !== -1) {
array.splice(index, 1);
}
}
The problem lies with the following line of code:
<mat-option *ngFor="let topping of toppingList" [value]="topping.id">
You are telling angular to use the id as value for the form control values. A solution would be to instead of using only the id, map these ids to topping objects themselves. Then your control is using topping objects instead of only a number. Here is the code you need to change:
<mat-chip
*ngFor="let topping of idsToToppings(toppingsControl.value)"
[removable]="true"
(removed)="onToppingRemoved(topping.id)"
>
{{ topping.name }}
and add the following method in your component:
idsToToppings(ids: number[]) : any[] {
return ids.map((id) => {
return this.toppingList.find((t) => t.id == id);
});
}