diff --git a/src/material-experimental/mdc-autocomplete/autocomplete-trigger.ts b/src/material-experimental/mdc-autocomplete/autocomplete-trigger.ts index 97f9a89eb8f5..b5ffb3a1108b 100644 --- a/src/material-experimental/mdc-autocomplete/autocomplete-trigger.ts +++ b/src/material-experimental/mdc-autocomplete/autocomplete-trigger.ts @@ -41,6 +41,7 @@ export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any = { '(blur)': '_onTouched()', '(input)': '_handleInput($event)', '(keydown)': '_handleKeydown($event)', + '(click)': 'openPanel()', }, exportAs: 'matAutocompleteTrigger', providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR], diff --git a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts index 3f111ab66994..9e1ce349b6f5 100644 --- a/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts +++ b/src/material-experimental/mdc-autocomplete/autocomplete.spec.ts @@ -569,6 +569,31 @@ describe('MDC-based MatAutocomplete', () => { expect(input.hasAttribute('aria-haspopup')).toBe(false); }); + + it('should close the panel when pressing escape', fakeAsync(() => { + const trigger = fixture.componentInstance.trigger; + + input.focus(); + flush(); + fixture.detectChanges(); + + expect(document.activeElement).withContext('Expected input to be focused.').toBe(input); + expect(trigger.panelOpen).withContext('Expected panel to be open.').toBe(true); + + trigger.closePanel(); + fixture.detectChanges(); + + expect(document.activeElement) + .withContext('Expected input to continue to be focused.') + .toBe(input); + expect(trigger.panelOpen).withContext('Expected panel to be closed.').toBe(false); + + input.click(); + flush(); + fixture.detectChanges(); + + expect(trigger.panelOpen).withContext('Expected panel to reopen on click.').toBe(true); + })); }); it('should not close the panel when clicking on the input', fakeAsync(() => { diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index 059665bdaea7..c6047db003f8 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -245,8 +245,10 @@ export abstract class _MatAutocompleteTriggerBase /** Opens the autocomplete suggestion panel. */ openPanel(): void { - this._attachOverlay(); - this._floatLabel(); + if (!this.panelOpen) { + this._attachOverlay(); + this._floatLabel(); + } } /** Closes the autocomplete suggestion panel. */ @@ -800,6 +802,7 @@ export abstract class _MatAutocompleteTriggerBase '(blur)': '_onTouched()', '(input)': '_handleInput($event)', '(keydown)': '_handleKeydown($event)', + '(click)': 'openPanel()', }, exportAs: 'matAutocompleteTrigger', providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR], diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts index ef3b1f562948..8394f30a8893 100644 --- a/src/material/autocomplete/autocomplete.spec.ts +++ b/src/material/autocomplete/autocomplete.spec.ts @@ -566,6 +566,31 @@ describe('MatAutocomplete', () => { expect(input.hasAttribute('aria-haspopup')).toBe(false); }); + + it('should close the panel when pressing escape', fakeAsync(() => { + const trigger = fixture.componentInstance.trigger; + + input.focus(); + flush(); + fixture.detectChanges(); + + expect(document.activeElement).withContext('Expected input to be focused.').toBe(input); + expect(trigger.panelOpen).withContext('Expected panel to be open.').toBe(true); + + trigger.closePanel(); + fixture.detectChanges(); + + expect(document.activeElement) + .withContext('Expected input to continue to be focused.') + .toBe(input); + expect(trigger.panelOpen).withContext('Expected panel to be closed.').toBe(false); + + input.click(); + flush(); + fixture.detectChanges(); + + expect(trigger.panelOpen).withContext('Expected panel to reopen on click.').toBe(true); + })); }); it('should not close the panel when clicking on the input', fakeAsync(() => {