diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts index 3f111ab66994..3f344cd215e5 100644 --- a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts +++ b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts @@ -2706,6 +2706,217 @@ describe('MDC-based MatAutocomplete', () => { })); }); + describe('automatically selecting the active option', () => { + let fixture: ComponentFixture; + + beforeEach(() => { + fixture = createComponent(SimpleAutocomplete); + fixture.detectChanges(); + fixture.componentInstance.trigger.autocomplete.autoSelectActiveOption = true; + }); + + it( + 'should update the input value as the user is navigating, without changing the model ' + + 'value or closing the panel', + fakeAsync(() => { + const {trigger, stateCtrl, closedSpy} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('California'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + }), + ); + + it('should revert back to the last typed value if the user presses escape', fakeAsync(() => { + const {trigger, stateCtrl, closedSpy} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + typeInElement(input, 'al'); + fixture.detectChanges(); + tick(); + + expect(stateCtrl.value).toBe('al'); + expect(input.value).toBe('al'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBe('al'); + expect(input.value).toBe('Alabama'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); + fixture.detectChanges(); + + expect(stateCtrl.value).toBe('al'); + expect(input.value).toBe('al'); + expect(trigger.panelOpen).toBe(false); + expect(closedSpy).toHaveBeenCalledTimes(1); + })); + + it( + 'should clear the input if the user presses escape while there was a pending ' + + 'auto selection and there is no previous value', + fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + }), + ); + + it('should propagate the auto-selected value if the user clicks away', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchFakeEvent(document, 'click'); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'AL', name: 'Alabama'}); + expect(input.value).toBe('Alabama'); + })); + + it('should propagate the auto-selected value if the user tabs away', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchKeyboardEvent(input, 'keydown', TAB); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'AL', name: 'Alabama'}); + expect(input.value).toBe('Alabama'); + })); + + it('should propagate the auto-selected value if the user presses enter on it', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchKeyboardEvent(input, 'keydown', ENTER); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'AL', name: 'Alabama'}); + expect(input.value).toBe('Alabama'); + })); + + it('should allow the user to click on an option different from the auto-selected one', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + const options = overlayContainerElement.querySelectorAll( + 'mat-option', + ) as NodeListOf; + options[2].click(); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'FL', name: 'Florida'}); + expect(input.value).toBe('Florida'); + })); + }); + it('should have correct width when opened', () => { const widthFixture = createComponent(SimpleAutocomplete); widthFixture.componentInstance.width = 300; diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 059665bdaea7..c3cce6e591eb 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -42,7 +42,7 @@ import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import { _countGroupLabelsBeforeOption, _getOptionScrollPosition, - MatOption, + _MatOptionBase, MatOptionSelectionChange, } from '@angular/material/core'; import {MAT_FORM_FIELD, MatFormField} from '@angular/material/form-field'; @@ -128,6 +128,15 @@ export abstract class _MatAutocompleteTriggerBase */ private _canOpenOnNextFocus = true; + /** Value inside the input before we auto-selected an option. */ + private _valueBeforeAutoSelection: string | undefined; + + /** + * Current option that we have auto-selected as the user is navigating, + * but which hasn't been propagated to the model value yet. + */ + private _pendingAutoselectedOption: _MatOptionBase | null; + /** Stream of keyboard events that can close the panel. */ private readonly _closeKeyEventStream = new Subject(); @@ -263,6 +272,7 @@ export abstract class _MatAutocompleteTriggerBase } this.autocomplete._isOpen = this._overlayAttached = false; + this._pendingAutoselectedOption = null; if (this._overlayRef && this._overlayRef.hasAttached()) { this._overlayRef.detach(); @@ -329,7 +339,7 @@ export abstract class _MatAutocompleteTriggerBase }) as Observable; /** The currently active option, coerced to MatOption type. */ - get activeOption(): MatOption | null { + get activeOption(): _MatOptionBase | null { if (this.autocomplete && this.autocomplete._keyManager) { return this.autocomplete._keyManager.activeItem; } @@ -370,7 +380,7 @@ export abstract class _MatAutocompleteTriggerBase // Implemented as part of ControlValueAccessor. writeValue(value: any): void { - Promise.resolve().then(() => this._setTriggerValue(value)); + Promise.resolve(null).then(() => this._assignOptionValue(value)); } // Implemented as part of ControlValueAccessor. @@ -416,6 +426,15 @@ export abstract class _MatAutocompleteTriggerBase if (isArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) { this._scrollToOption(this.autocomplete._keyManager.activeItemIndex || 0); + + if (this.autocomplete.autoSelectActiveOption && this.activeOption) { + if (!this._pendingAutoselectedOption) { + this._valueBeforeAutoSelection = this._element.nativeElement.value; + } + + this._pendingAutoselectedOption = this.activeOption; + this._assignOptionValue(this.activeOption.value); + } } } } @@ -436,6 +455,7 @@ export abstract class _MatAutocompleteTriggerBase // See: https://connect.microsoft.com/IE/feedback/details/885747/ if (this._previousValue !== value) { this._previousValue = value; + this._pendingAutoselectedOption = null; this._onChange(value); if (this._canOpen() && this._document.activeElement === event.target) { @@ -535,7 +555,7 @@ export abstract class _MatAutocompleteTriggerBase } } - private _setTriggerValue(value: any): void { + private _assignOptionValue(value: any): void { const toDisplay = this.autocomplete && this.autocomplete.displayWith ? this.autocomplete.displayWith(value) @@ -543,17 +563,19 @@ export abstract class _MatAutocompleteTriggerBase // Simply falling back to an empty string if the display value is falsy does not work properly. // The display value can also be the number zero and shouldn't fall back to an empty string. - const inputValue = toDisplay != null ? toDisplay : ''; + this._updateNativeInputValue(toDisplay != null ? toDisplay : ''); + } + private _updateNativeInputValue(value: string): void { // If it's used within a `MatFormField`, we should set it through the property so it can go // through change detection. if (this._formField) { - this._formField._control.value = inputValue; + this._formField._control.value = value; } else { - this._element.nativeElement.value = inputValue; + this._element.nativeElement.value = value; } - this._previousValue = inputValue; + this._previousValue = value; } /** @@ -562,13 +584,13 @@ export abstract class _MatAutocompleteTriggerBase * stemmed from the user. */ private _setValueAndClose(event: MatOptionSelectionChange | null): void { - const source = event && event.source; + const toSelect = event ? event.source : this._pendingAutoselectedOption; - if (source) { - this._clearPreviousSelectedOption(source); - this._setTriggerValue(source.value); - this._onChange(source.value); - this.autocomplete._emitSelectEvent(source); + if (toSelect) { + this._clearPreviousSelectedOption(toSelect); + this._assignOptionValue(toSelect.value); + this._onChange(toSelect.value); + this.autocomplete._emitSelectEvent(toSelect); this._element.nativeElement.focus(); } @@ -578,7 +600,7 @@ export abstract class _MatAutocompleteTriggerBase /** * Clear any previous selected option and emit a selection change event for this option */ - private _clearPreviousSelectedOption(skip: MatOption) { + private _clearPreviousSelectedOption(skip: _MatOptionBase) { this.autocomplete.options.forEach(option => { if (option !== skip && option.selected) { option.deselect(); @@ -599,26 +621,7 @@ export abstract class _MatAutocompleteTriggerBase }); overlayRef = this._overlay.create(this._getOverlayConfig()); this._overlayRef = overlayRef; - - // Use the `keydownEvents` in order to take advantage of - // the overlay event targeting provided by the CDK overlay. - overlayRef.keydownEvents().subscribe(event => { - // Close when pressing ESCAPE or ALT + UP_ARROW, based on the a11y guidelines. - // See: https://www.w3.org/TR/wai-aria-practices-1.1/#textbox-keyboard-interaction - if ( - (event.keyCode === ESCAPE && !hasModifierKey(event)) || - (event.keyCode === UP_ARROW && hasModifierKey(event, 'altKey')) - ) { - this._closeKeyEventStream.next(); - this._resetActiveItem(); - - // We need to stop propagation, otherwise the event will eventually - // reach the input itself and cause the overlay to be reopened. - event.stopPropagation(); - event.preventDefault(); - } - }); - + this._handleOverlayEvents(overlayRef); this._viewportSubscription = this._viewportRuler.change().subscribe(() => { if (this.panelOpen && overlayRef) { overlayRef.updateSize({width: this._getPanelWidth()}); @@ -781,6 +784,35 @@ export abstract class _MatAutocompleteTriggerBase } } } + + /** Handles keyboard events coming from the overlay panel. */ + private _handleOverlayEvents(overlayRef: OverlayRef) { + // Use the `keydownEvents` in order to take advantage of + // the overlay event targeting provided by the CDK overlay. + overlayRef.keydownEvents().subscribe(event => { + // Close when pressing ESCAPE or ALT + UP_ARROW, based on the a11y guidelines. + // See: https://www.w3.org/TR/wai-aria-practices-1.1/#textbox-keyboard-interaction + if ( + (event.keyCode === ESCAPE && !hasModifierKey(event)) || + (event.keyCode === UP_ARROW && hasModifierKey(event, 'altKey')) + ) { + // If the user had typed something in before we autoselected an option, and they decided + // to cancel the selection, restore the input value to the one they had typed in. + if (this._pendingAutoselectedOption) { + this._updateNativeInputValue(this._valueBeforeAutoSelection ?? ''); + this._pendingAutoselectedOption = null; + } + + this._closeKeyEventStream.next(); + this._resetActiveItem(); + + // We need to stop propagation, otherwise the event will eventually + // reach the input itself and cause the overlay to be reopened. + event.stopPropagation(); + event.preventDefault(); + } + }); + } } @Directive({ diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index ef3b1f562948..70847a76a6df 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -2708,6 +2708,217 @@ describe('MatAutocomplete', () => { })); }); + describe('automatically selecting the active option', () => { + let fixture: ComponentFixture; + + beforeEach(() => { + fixture = createComponent(SimpleAutocomplete); + fixture.detectChanges(); + fixture.componentInstance.trigger.autocomplete.autoSelectActiveOption = true; + }); + + it( + 'should update the input value as the user is navigating, without changing the model ' + + 'value or closing the panel', + fakeAsync(() => { + const {trigger, stateCtrl, closedSpy} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('California'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + }), + ); + + it('should revert back to the last typed value if the user presses escape', fakeAsync(() => { + const {trigger, stateCtrl, closedSpy} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + typeInElement(input, 'al'); + fixture.detectChanges(); + tick(); + + expect(stateCtrl.value).toBe('al'); + expect(input.value).toBe('al'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBe('al'); + expect(input.value).toBe('Alabama'); + expect(trigger.panelOpen).toBe(true); + expect(closedSpy).not.toHaveBeenCalled(); + + dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); + fixture.detectChanges(); + + expect(stateCtrl.value).toBe('al'); + expect(input.value).toBe('al'); + expect(trigger.panelOpen).toBe(false); + expect(closedSpy).toHaveBeenCalledTimes(1); + })); + + it( + 'should clear the input if the user presses escape while there was a pending ' + + 'auto selection and there is no previous value', + fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchKeyboardEvent(document.body, 'keydown', ESCAPE); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + }), + ); + + it('should propagate the auto-selected value if the user clicks away', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchFakeEvent(document, 'click'); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'AL', name: 'Alabama'}); + expect(input.value).toBe('Alabama'); + })); + + it('should propagate the auto-selected value if the user tabs away', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchKeyboardEvent(input, 'keydown', TAB); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'AL', name: 'Alabama'}); + expect(input.value).toBe('Alabama'); + })); + + it('should propagate the auto-selected value if the user presses enter on it', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + dispatchKeyboardEvent(input, 'keydown', ENTER); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'AL', name: 'Alabama'}); + expect(input.value).toBe('Alabama'); + })); + + it('should allow the user to click on an option different from the auto-selected one', fakeAsync(() => { + const {trigger, stateCtrl} = fixture.componentInstance; + const input: HTMLInputElement = fixture.nativeElement.querySelector('input'); + + trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBeFalsy(); + + dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW); + fixture.detectChanges(); + + expect(stateCtrl.value).toBeFalsy(); + expect(input.value).toBe('Alabama'); + + const options = overlayContainerElement.querySelectorAll( + 'mat-option', + ) as NodeListOf; + options[2].click(); + fixture.detectChanges(); + + expect(stateCtrl.value).toEqual({code: 'FL', name: 'Florida'}); + expect(input.value).toBe('Florida'); + })); + }); + it('should have correct width when opened', () => { const widthFixture = createComponent(SimpleAutocomplete); widthFixture.componentInstance.width = 300; diff --git a/src/material/autocomplete/autocomplete.ts b/src/material/autocomplete/autocomplete.ts index ad025695f812..17926ec049c0 100644 --- a/src/material/autocomplete/autocomplete.ts +++ b/src/material/autocomplete/autocomplete.ts @@ -74,6 +74,9 @@ export interface MatAutocompleteDefaultOptions { /** Whether the first option should be highlighted when an autocomplete panel is opened. */ autoActiveFirstOption?: boolean; + /** Whether the active option should be selected as the user is navigating. */ + autoSelectActiveOption?: boolean; + /** Class or list of classes to be applied to the autocomplete's overlay panel. */ overlayPanelClass?: string | string[]; } @@ -89,7 +92,7 @@ export const MAT_AUTOCOMPLETE_DEFAULT_OPTIONS = new InjectionToken; protected abstract _visibleClass: string; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration<_MatAutocompleteBase, never, never, { "ariaLabel": "aria-label"; "ariaLabelledby": "aria-labelledby"; "displayWith": "displayWith"; "autoActiveFirstOption": "autoActiveFirstOption"; "panelWidth": "panelWidth"; "classList": "class"; }, { "optionSelected": "optionSelected"; "opened": "opened"; "closed": "closed"; "optionActivated": "optionActivated"; }, never>; + static ɵdir: i0.ɵɵDirectiveDeclaration<_MatAutocompleteBase, never, never, { "ariaLabel": "aria-label"; "ariaLabelledby": "aria-labelledby"; "displayWith": "displayWith"; "autoActiveFirstOption": "autoActiveFirstOption"; "autoSelectActiveOption": "autoSelectActiveOption"; "panelWidth": "panelWidth"; "classList": "class"; }, { "optionSelected": "optionSelected"; "opened": "opened"; "closed": "closed"; "optionActivated": "optionActivated"; }, never>; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration<_MatAutocompleteBase, never>; } @@ -135,6 +137,7 @@ export abstract class _MatAutocompleteBase extends _MatAutocompleteMixinBase imp // @public export interface MatAutocompleteDefaultOptions { autoActiveFirstOption?: boolean; + autoSelectActiveOption?: boolean; overlayPanelClass?: string | string[]; } @@ -190,7 +193,7 @@ export class MatAutocompleteTrigger extends _MatAutocompleteTriggerBase { export abstract class _MatAutocompleteTriggerBase implements ControlValueAccessor, AfterViewInit, OnChanges, OnDestroy { constructor(_element: ElementRef, _overlay: Overlay, _viewContainerRef: ViewContainerRef, _zone: NgZone, _changeDetectorRef: ChangeDetectorRef, scrollStrategy: any, _dir: Directionality, _formField: MatFormField, _document: any, _viewportRuler: ViewportRuler, _defaults?: MatAutocompleteDefaultOptions | undefined); protected abstract _aboveClass: string; - get activeOption(): MatOption | null; + get activeOption(): _MatOptionBase | null; autocomplete: _MatAutocompleteBase; autocompleteAttribute: string; get autocompleteDisabled(): boolean;