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: `