0
votes

I'm working in Angular 7 and one of the requirements that I have is to create a mat-select with mat-icons. The issue I'm up against is I can either get the icons to show or I can get the option label to show but not both. What I need to do is be able to chain the value, but I got an error when I tried.

The mat-select is set up as so-

    <button mat-raised-button type="button" name="button" color="primary" class="roundedButton">
    <mat-select [(value)]="selected2">
      <mat-select-trigger><mat-icon>{{selected2}}</mat-icon>{{selected2}}</mat-select-trigger>
      <mat-option *ngFor="let food of foods" [value]="food.value">
        <mat-icon>{{food.icon}}</mat-icon>{{food.viewValue}}
      </mat-option>
    </mat-select>
    </button>
</mat-form-field>

I have placed the selected icon and label in the mat-select-trigger and the value to food.value.

The interface for the select is

export interface Food {
  value: string;
  viewValue: string;
  icon: any;
}

and the select options are set up as

  foods: Food[] = [
    {value: 'steak-0', icon: 'add', viewValue: 'Steak'},
    {value: 'pizza-1', icon: 'lock', viewValue: 'Pizza'},
    {value: 'tacos-2', icon: 'search', viewValue: 'Tacos'}
  ];
    public selected2 = 'steak-0';

If I change the value to be food.icon I can get the select options icon to appear as the selection. If I change value to food.viewValue I get the label of the option to appear.

How can I get both when a user makes a selection?

I have set up a Stackblitz to show the setup and issue in action.

Thank you in advance!

2

2 Answers

3
votes

Instead of setting the value to the icon or the viewValue, set it to the entire object. This way the selected value will contain the data in the entire object. Then you can simply use the properties in the selected object to get what you want.

<mat-form-field>
    <button mat-raised-button type="button" name="button" color="primary" class="roundedButton">
        <mat-select [(value)]="selected2" [compareWith]="compareFn">
            <mat-select-trigger><mat-icon class="selection-icon">{{selected2.icon}}</mat-icon><span>{{selected2.viewValue}}</span></mat-select-trigger>
            <mat-option *ngFor="let food of foods" [value]="food">
                <mat-icon>{{food.icon}}</mat-icon>{{food.viewValue}}
            </mat-option>
        </mat-select>
    </button>
</mat-form-field>

Now both icon and viewValue will show in the select trigger. All you need to is fic the css of the icon since it doesn't appear inline with the viewValue.

.selection-icon {
    position: relative;
    top: 6px;
    margin-right: 16px;
}

Here is a working example.

Note: In order to set the value of this selected object, you can either pass an object from the original array itself (for eg. public selected2 = foods[0]) or you can use compareWith so that the select will be able to track the values since our option value is an object. This is similar to the trackBy in ngFor. Basically, either pass a reference from the original array so the select can track it or use compareWith to tell the select to track the objects in the arrays based on some unique value in each object.

1
votes

You can try the code below:

<mat-select #select>
  <mat-select-trigger *ngIf="select.value"><mat-icon>{{select.value.icon}}</mat-icon>{{select.value.viewValue}}</mat-select-trigger>
  <mat-option *ngFor="let food of foods" [value]="food">
    <mat-icon>{{food.icon}}</mat-icon>{{food.viewValue}}
  </mat-option>
</mat-select>