I have a mat-select where the options are all objects defined in an array. I am trying to set the value to default to one of the options, however it is being left selected
I did this.
<div>
<mat-select [(ngModel)]="selected">
<mat-option *ngFor="let option of options"
[value]="option.id === selected.id ? selected : option">
{{ option.name }}
</mat-option>
</mat-select>
</div>
Normally you can do [value]="option"
, unless you get your options from some database?? I think either the delay of getting the data causes it not to work, or the objects gotten are different in some way even though they are the same??
Weirdly enough it's most likely the later one, as I also tried [value]="option === selected ? selected : option"
and it didn't work.
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.
A very simple way to achieve this is using a formControl
with a default value, inside a FormGroup
(optional) for example. This is an example using an unit selector to an area input:
ts
H_AREA_UNIT = 1;
M_AREA_UNIT = 2;
exampleForm: FormGroup;
this.exampleForm = this.formBuilder.group({
areaUnit: [this.H_AREA_UNIT],
});
html
<form [formGroup]="exampleForm">
<mat-form-field>
<mat-label>Unit</mat-label>
<mat-select formControlName="areaUnit">
<mat-option [value]="H_AREA_UNIT">h</mat-option>
<mat-option [value]="M_AREA_UNIT">m</mat-option>
</mat-select>
</mat-form-field>
</form>
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>
The solution for me was:
<mat-form-field>
<mat-select #monedaSelect formControlName="monedaDebito" [attr.disabled]="isLoading" [placeholder]="monedaLabel | async ">
<mat-option *ngFor="let moneda of monedasList" [value]="moneda.id">{{moneda.detalle}}</mat-option>
</mat-select>
TS:
@ViewChild('monedaSelect') public monedaSelect: MatSelect;
this.genericService.getOpciones().subscribe(res => {
this.monedasList = res;
this.monedaSelect._onChange(res[0].id);
});
Using object: {id: number, detalle: string}