From 1a4e9eac2118b11eb2144d0f387ca7d14c02782d Mon Sep 17 00:00:00 2001 From: Karan Mistry Date: Sat, 27 Sep 2025 13:39:57 +0530 Subject: [PATCH] fix(material/autocomplete): add support for initial value in form control Currently, when we have some initial value in formcontrol those are not marked as selected, this fix will check the initial value and if its matched, will be marked as selected. Fixes #29422 --- .../autocomplete/autocomplete-trigger.ts | 13 ++++ .../autocomplete/autocomplete.spec.ts | 61 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 486c7a60728a..1d89ede13987 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -206,6 +206,9 @@ export class MatAutocompleteTrigger this._canOpenOnNextFocus = this.panelOpen || !this._hasFocus(); }; + /** Value of the autocomplete control. */ + private _value: any; + /** `View -> model callback called when value changes` */ _onChange: (value: any) => void = () => {}; @@ -252,6 +255,15 @@ export class MatAutocompleteTrigger ngAfterViewInit() { this._initialized.next(); this._initialized.complete(); + if (this._value) { + const selectedOption = this.autocomplete?.options?.find( + o => this._getDisplayValue(o.value) === this._getDisplayValue(this._value), + ); + if (selectedOption && !selectedOption.selected) { + selectedOption.select(false); + this._changeDetectorRef.detectChanges(); + } + } this._cleanupWindowBlur = this._renderer.listen('window', 'blur', this._windowBlurHandler); } @@ -434,6 +446,7 @@ export class MatAutocompleteTrigger // Implemented as part of ControlValueAccessor. writeValue(value: any): void { + this._value = value; Promise.resolve(null).then(() => this._assignOptionValue(value)); } diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index c335f8e85b27..bf84336ab751 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -1614,6 +1614,36 @@ describe('MatAutocomplete', () => { }); }); + describe('form control with initial value', () => { + let fixture: ComponentFixture; + let input: HTMLInputElement; + + beforeEach(waitForAsync(async () => { + fixture = createComponent(FormControlWithInitialValue); + fixture.detectChanges(); + + input = fixture.debugElement.query(By.css('input'))!.nativeElement; + + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + await new Promise(r => setTimeout(r)); + })); + + it('should mark the initial value as selected if its present', fakeAsync(() => { + const trigger = fixture.componentInstance.trigger; + trigger.openPanel(); + fixture.detectChanges(); + + const options = overlayContainerElement.querySelectorAll( + 'mat-option', + ) as NodeListOf; + + expect(input.value).toBe('Three'); + expect(options.length).toBe(3); + expect(options[2].classList).toContain('mdc-list-item--selected'); + })); + }); + describe('option groups', () => { let DOWN_ARROW_EVENT: KeyboardEvent; let UP_ARROW_EVENT: KeyboardEvent; @@ -4414,6 +4444,37 @@ class PlainAutocompleteInputWithFormControl { formControl = new FormControl(''); } +@Component({ + template: ` + + + + + @for (option of options; track option) { + + {{option}} + +} + + `, + imports: [ + MatAutocomplete, + MatAutocompleteTrigger, + MatOption, + MatInputModule, + ReactiveFormsModule, + ], +}) +class FormControlWithInitialValue { + optionCtrl = new FormControl('Three'); + filteredOptions: Observable; + options = ['One', 'Two', 'Three']; + + @ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger; + + constructor() {} +} + @Component({ template: `