From 5e0ebad651e5edf2d028e48a3098f661968f7e49 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Thu, 26 Oct 2017 23:05:09 +0200 Subject: [PATCH] fix(select): closing parent overlay when pressing escape After the switch to `ActiveDescendantKeyManager`, the select was no longer handling the escape key functionality internally, but was delegating to the underlying overlay. Since the overlay listens to keyboard events on the document, it means that escape key presses will close any parent overlays along the way. These changes add the escape listener to the select itself and stop the event propagation. **Note:** the overlay directive listener should be scoped to the overlay itself, but it's better if we defer refactoring it until #6682 gets in. Fixes #7981. --- src/lib/select/select.spec.ts | 15 ++++++++++++++- src/lib/select/select.ts | 5 ++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts index d840b3198d46..e9177b8bdf6a 100644 --- a/src/lib/select/select.spec.ts +++ b/src/lib/select/select.spec.ts @@ -1,5 +1,5 @@ import {Directionality} from '@angular/cdk/bidi'; -import {DOWN_ARROW, END, ENTER, HOME, SPACE, TAB, UP_ARROW} from '@angular/cdk/keycodes'; +import {DOWN_ARROW, END, ENTER, HOME, SPACE, TAB, UP_ARROW, ESCAPE} from '@angular/cdk/keycodes'; import {OverlayContainer} from '@angular/cdk/overlay'; import {Platform} from '@angular/cdk/platform'; import {ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling'; @@ -275,6 +275,19 @@ describe('MatSelect', () => { expect(fixture.componentInstance.select.panelOpen).toBe(false); })); + it('should close the panel when pressing escape', fakeAsync(() => { + trigger.click(); + fixture.detectChanges(); + tick(SELECT_OPEN_ANIMATION); + expect(fixture.componentInstance.select.panelOpen).toBe(true); + + dispatchKeyboardEvent(trigger, 'keydown', ESCAPE); + fixture.detectChanges(); + tick(SELECT_CLOSE_ANIMATION); + + expect(fixture.componentInstance.select.panelOpen).toBe(false); + })); + it('should focus the first option when pressing HOME', fakeAsync(() => { fixture.componentInstance.control.setValue('pizza-1'); fixture.detectChanges(); diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index 8ad70fc9d2dd..357553d6d56f 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -10,7 +10,7 @@ import {ActiveDescendantKeyManager} from '@angular/cdk/a11y'; import {Directionality} from '@angular/cdk/bidi'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {SelectionModel} from '@angular/cdk/collections'; -import {DOWN_ARROW, END, ENTER, HOME, SPACE, UP_ARROW} from '@angular/cdk/keycodes'; +import {DOWN_ARROW, END, ENTER, HOME, SPACE, UP_ARROW, ESCAPE} from '@angular/cdk/keycodes'; import { ConnectedOverlayDirective, Overlay, @@ -628,6 +628,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, } else if ((keyCode === ENTER || keyCode === SPACE) && this._keyManager.activeItem) { event.preventDefault(); this._keyManager.activeItem._selectViaInteraction(); + } else if (keyCode === ESCAPE) { + event.stopPropagation(); + this.close(); } else { this._keyManager.onKeydown(event); }