From 78561ab23d3f3e0854d181f4fe14cdfd609066f1 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 25 Feb 2022 13:00:54 +0100 Subject: [PATCH] fix(material/autocomplete): reopen panel on input click Currently if the user clicks an autocomplete to open it, selects an option and then clicks again, the panel won't open, because we use `focus` and the input was focused already. These changes add an extra `click` listener so the panel can reopen. Fixes #15177. --- .../mdc-autocomplete/autocomplete-trigger.ts | 1 + .../mdc-autocomplete/autocomplete.spec.ts | 25 +++++++++++++++++++ .../autocomplete/autocomplete-trigger.ts | 7 ++++++ .../autocomplete/autocomplete.spec.ts | 25 +++++++++++++++++++ 4 files changed, 58 insertions(+) diff --git a/src/material-experimental/mdc-autocomplete/autocomplete-trigger.ts b/src/material-experimental/mdc-autocomplete/autocomplete-trigger.ts index 97f9a89eb8f5..4c2196b28c5b 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)': '_handleClick()', }, 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..b328223f0545 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -454,6 +454,12 @@ export abstract class _MatAutocompleteTriggerBase } } + _handleClick(): void { + if (this._canOpen() && !this.panelOpen) { + this.openPanel(); + } + } + /** * In "auto" mode, the label will animate down as soon as focus is lost. * This causes the value to jump when selecting an option with the mouse. @@ -800,6 +806,7 @@ export abstract class _MatAutocompleteTriggerBase '(blur)': '_onTouched()', '(input)': '_handleInput($event)', '(keydown)': '_handleKeydown($event)', + '(click)': '_handleClick()', }, 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(() => {