When using Angular Mat Auto complete and the value to the auto complete is set programmatically, the selected option won't show the selected tick mark beside the selected option
I'm using Angular V15 and Angular Material V15
Stackblitz Link
Thanks in Advance!
This is a small issue which is easily replicable on the examples.
Would suggest a small workaround. When you programmatically update the value, then you can fire a function. This will find the correct option then call the method _selectViaInteraction
which will trigger the selection as well as show the checkbox.
ngAfterViewInit() {
this.triggerProgrammaticSelection();
}
triggerProgrammaticSelection() {
const formValue = this.stateForm.get('stateGroupFiltered')!.value;
const foundOption = this.autoComplete.options.find(
(matOption: MatOption) => matOption.value === formValue
);
if (foundOption) {
foundOption._selectViaInteraction();
}
}
Github issue which helped to solve
import { Component, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Observable } from 'rxjs';
import { startWith, map } from 'rxjs/operators';
import { NgFor, AsyncPipe } from '@angular/common';
import {
MatAutocomplete,
MatAutocompleteModule,
} from '@angular/material/autocomplete';
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatOption } from '@angular/material/core';
export interface StateGroup {
letter: string;
names: string[];
}
export const _filter = (opt: string[], value: string): string[] => {
const filterValue = value.toLowerCase();
return opt.filter((item) => item.toLowerCase().includes(filterValue));
};
/**
* @title Option groups autocomplete
*/
@Component({
selector: 'autocomplete-optgroup-example',
templateUrl: 'autocomplete-optgroup-example.html',
standalone: true,
imports: [
FormsModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
MatAutocompleteModule,
NgFor,
AsyncPipe,
],
})
export class AutocompleteOptgroupExample implements OnInit {
@ViewChild(MatAutocomplete) autoComplete!: MatAutocomplete;
stateForm = this._formBuilder.group({
stateGroupFiltered: 'Alaska',
stateGroupNotFiltered: 'Alaska',
});
trackByFn = (_: number, item: StateGroup): string => {
return item.letter;
};
stateGroups: StateGroup[] = [
{
letter: 'A',
names: ['Alabama', 'Alaska', 'Arizona', 'Arkansas'],
},
{
letter: 'C',
names: ['California', 'Colorado', 'Connecticut'],
},
{
letter: 'D',
names: ['Delaware'],
},
{
letter: 'F',
names: ['Florida'],
},
{
letter: 'G',
names: ['Georgia'],
},
{
letter: 'H',
names: ['Hawaii'],
},
{
letter: 'I',
names: ['Idaho', 'Illinois', 'Indiana', 'Iowa'],
},
{
letter: 'K',
names: ['Kansas', 'Kentucky'],
},
{
letter: 'L',
names: ['Louisiana'],
},
{
letter: 'M',
names: [
'Maine',
'Maryland',
'Massachusetts',
'Michigan',
'Minnesota',
'Mississippi',
'Missouri',
'Montana',
],
},
{
letter: 'N',
names: [
'Nebraska',
'Nevada',
'New Hampshire',
'New Jersey',
'New Mexico',
'New York',
'North Carolina',
'North Dakota',
],
},
{
letter: 'O',
names: ['Ohio', 'Oklahoma', 'Oregon'],
},
{
letter: 'P',
names: ['Pennsylvania'],
},
{
letter: 'R',
names: ['Rhode Island'],
},
{
letter: 'S',
names: ['South Carolina', 'South Dakota'],
},
{
letter: 'T',
names: ['Tennessee', 'Texas'],
},
{
letter: 'U',
names: ['Utah'],
},
{
letter: 'V',
names: ['Vermont', 'Virginia'],
},
{
letter: 'W',
names: ['Washington', 'West Virginia', 'Wisconsin', 'Wyoming'],
},
];
stateGroupOptions: Observable<StateGroup[]>;
constructor(private _formBuilder: FormBuilder) {}
ngAfterViewInit() {
this.triggerProgrammaticSelection();
}
triggerProgrammaticSelection() {
const formValue = this.stateForm.get('stateGroupFiltered')!.value;
const foundOption = this.autoComplete.options.find(
(matOption: MatOption) => matOption.value === formValue
);
if (foundOption) {
foundOption._selectViaInteraction();
}
}
ngOnInit() {
this.stateGroupOptions = this.stateForm
.get('stateGroupFiltered')!
.valueChanges.pipe(
startWith(''),
map((value) => this._filterGroup(value || ''))
);
}
private _filterGroup(value: string): StateGroup[] {
if (value) {
return this.stateGroups
.map((group) => ({
letter: group.letter,
names: _filter(group.names, value),
}))
.filter((group) => group.names.length > 0);
}
return this.stateGroups;
}
}
<form [formGroup]="stateForm">
<mat-form-field>
<mat-label>Filtered States Group</mat-label>
<input
type="text"
matInput
formControlName="stateGroupFiltered"
required
[matAutocomplete]="autoGroup"
/>
<!-- #docregion mat-autocomplete -->
<mat-autocomplete #autoGroup="matAutocomplete">
<mat-optgroup
[label]="group.letter"
*ngFor="let group of stateGroupOptions | async; trackBy: trackByFn"
>
<mat-option *ngFor="let name of group.names" [value]="name">
{{name}}
</mat-option>
</mat-optgroup>
</mat-autocomplete>
<!-- #enddocregion mat-autocomplete -->
</mat-form-field>
<br />
<mat-form-field>
<mat-label>Not Filtered States Group</mat-label>
<input
type="text"
matInput
formControlName="stateGroupNotFiltered"
required
[matAutocomplete]="autoGroup2"
/>
<!-- #docregion mat-autocomplete -->
<mat-autocomplete #autoGroup2="matAutocomplete">
<mat-optgroup *ngFor="let group of stateGroups" [label]="group.letter">
<mat-option *ngFor="let name of group.names" [value]="name">
{{name}}
</mat-option>
</mat-optgroup>
</mat-autocomplete>
<!-- #enddocregion mat-autocomplete -->
</mat-form-field>
</form>