angularangular-materialmat-chip

How to show selected name in angular material multi select checkbox and chips component


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

Demo

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);
    }
  }

Current Result (image 1): enter image description here

Expected Result (image 2): enter image description here

  1. List item

Solution

  • 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);
        });
      }