Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Material: mat-select not selecting default

People also ask

How does mat-select set value?

Angular Material Select is created using <mat-select> which is a form control for selecting a value from a set of options. To add elements to Select option, we need to use <mat-option> element and to bind value with <mat-option> , use value property of it.

What is compareWith in mat-select?

The compareWith just literally compares objects by some given values and the checkboxes get selected, if it returns true . In my code, I decided to go with the ng-Model binding but it works with formControl as well: <mat-form-field>

What is Mat Optgroup for?

The <mat-optgroup> element can be used to group common options under a subheading. The name of the group can be set using the label property of <mat-optgroup> . Like individual <mat-option> elements, an entire <mat-optgroup> can be disabled or enabled by setting the disabled property on the group.


Use a binding for the value in your template.

value="{{ option.id }}"

should be

[value]="option.id"

And in your selected value use ngModel instead of value.

<mat-select [(value)]="selected2">

should be

<mat-select [(ngModel)]="selected2">

Complete code:

<div>
  <mat-select [(ngModel)]="selected2">
    <mat-option *ngFor="let option of options2" [value]="option.id">{{ option.name }}</mat-option>
  </mat-select>
</div>

On a side note as of version 2.0.0-beta.12 the material select now accepts a mat-form-field element as the parent element so it is consistent with the other material input controls. Replace the div element with mat-form-field element after you upgrade.

<mat-form-field>
  <mat-select [(ngModel)]="selected2">
    <mat-option *ngFor="let option of options2" [value]="option.id">{{ option.name }}</mat-option>
  </mat-select>
</mat-form-field>

Use compareWith, A function to compare the option values with the selected values. see here: https://material.angular.io/components/select/api#MatSelect

For an object of the following structure:

listOfObjs = [{ name: 'john', id: '1'}, { name: 'jimmy', id: '2'},...]

Define markup like this:

<mat-form-field>
  <mat-select
    [compareWith]="compareObjects"
    [(ngModel)]="obj">
       <mat-option  *ngFor="let obj of listOfObjs" [value]="obj">
          {{ obj.name }}
       </mat-option>
    </mat-select>
</mat-form-field>

And define comparison function like this:

compareObjects(o1: any, o2: any): boolean {
  return o1.name === o2.name && o1.id === o2.id;
}

I'm using Angular 5 and reactive forms with mat-select and couldn't get either of the above solutions to display the initial value.

I had to add [compareWith] to deal with the different types being used within the mat-select component. Internally, it appears mat-select uses an array to hold the selected value. This is likely to allow the same code to work with multiple selections if that mode is turned on.

Angular Select Control Doc

Here's my solution:

Form Builder to initialize the form control:

this.formGroup = this.fb.group({
    country: new FormControl([ this.myRecord.country.id ] ),
    ...
});

Then implement the compareWith function on your component:

compareIds(id1: any, id2: any): boolean {
    const a1 = determineId(id1);
    const a2 = determineId(id2);
    return a1 === a2;
}

Next create and export the determineId function (I had to create a standalone function so mat-select could use it):

export function determineId(id: any): string {
    if (id.constructor.name === 'array' && id.length > 0) {
       return '' + id[0];
    }
    return '' + id;
}

Finally add the compareWith attribute to your mat-select:

<mat-form-field hintLabel="select one">
<mat-select placeholder="Country" formControlName="country" 
    [compareWith]="compareIds">

    <mat-option>None</mat-option>
    <mat-option *ngFor="let country of countries" [value]="country.id">
                        {{ country.name }}
    </mat-option>
</mat-select>
</mat-form-field>

You should be binding it as [value] in the mat-option as below,

<mat-select placeholder="Panel color" [(value)]="selected2">
  <mat-option *ngFor="let option of options2" [value]="option.id">
    {{ option.name }}
  </mat-option>
</mat-select>

LIVE DEMO


You can simply implement your own compare function

[compareWith]="compareItems"

See as well the docu. So the complete code would look like:

  <div>
    <mat-select
        [(value)]="selected2" [compareWith]="compareItems">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

and in the Typescript file:

  compareItems(i1, i2) {
    return i1 && i2 && i1.id===i2.id;
  }

As already mentioned in Angular 6 using ngModel in reactive forms is deprecated (and removed in Angular 7), so I modified the template and the component as following.

The template:

<mat-form-field>
    <mat-select [formControl]="filter" multiple 
                [compareWith]="compareFn">
        <mat-option *ngFor="let v of values" [value]="v">{{v.label}}</mat-option>
    </mat-select>
</mat-form-field>

The main parts of the component (onChanges and other details are omitted):

interface SelectItem {
    label: string;
    value: any;
}

export class FilterComponent implements OnInit {
    filter = new FormControl();

    @Input
    selected: SelectItem[] = [];

    @Input()
    values: SelectItem[] = [];

    constructor() { }

    ngOnInit() {
        this.filter.setValue(this.selected);
    }

    compareFn(v1: SelectItem, v2: SelectItem): boolean {
        return compareFn(v1, v2);
    }
}

function compareFn(v1: SelectItem, v2: SelectItem): boolean {
    return v1 && v2 ? v1.value === v2.value : v1 === v2;
}

Note this.filter.setValue(this.selected) in ngOnInit above.

It seems to work in Angular 6.


I did it just like in these examples. Tried to set the value of the mat-select to the value of one of the mat-options. But failed.

My mistake was to do [(value)]="someNumberVariable" to a numeric type variable while the ones in mat-options were strings. Even if they looked the same in the template it would not select that option.

Once I parsed the someNumberVariable to a string everything was totally fine.

So it seems you need to have the mat-select and the mat-option values not only be the same number (if you are presenting numbers) but also let them be of type string.