diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index c723970f3b4f..7e5b08552772 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -219,6 +219,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 = () => {}; @@ -265,6 +268,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); } @@ -447,6 +459,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 63f062d90f48..a484156a219b 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -1617,6 +1617,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; @@ -4375,6 +4405,31 @@ class PlainAutocompleteInputWithFormControl { formControl = new FormControl(''); } +@Component({ + template: ` + + + + + @for (option of options; track option) { + + {{option}} + +} + + `, + standalone: false, +}) +class FormControlWithInitialValue { + optionCtrl = new FormControl('Three'); + filteredOptions: Observable; + options = ['One', 'Two', 'Three']; + + @ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger; + + constructor() {} +} + @Component({ template: `