From a831bf652c110a834018fdcb80c3da54f34fec61 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 10 Jul 2018 16:34:36 +0200 Subject: [PATCH] feat(overlay): expose keydown events on the opened overlay (#11867) Since the consumer doesn't have direct access to the overlay that is being opened, there's no way for them to listen for keyboard events. These changes expose the `OverlayRef.keydownEvents` via an output. --- src/cdk/overlay/overlay-directives.spec.ts | 18 ++++++++++++++++-- src/cdk/overlay/overlay-directives.ts | 5 +++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/cdk/overlay/overlay-directives.spec.ts b/src/cdk/overlay/overlay-directives.spec.ts index 3c57df92910..875a0a16ecc 100644 --- a/src/cdk/overlay/overlay-directives.spec.ts +++ b/src/cdk/overlay/overlay-directives.spec.ts @@ -3,7 +3,7 @@ import {By} from '@angular/platform-browser'; import {ComponentFixture, TestBed, async, inject} from '@angular/core/testing'; import {Directionality} from '@angular/cdk/bidi'; import {dispatchKeyboardEvent} from '@angular/cdk/testing'; -import {ESCAPE} from '@angular/cdk/keycodes'; +import {ESCAPE, A} from '@angular/cdk/keycodes'; import {CdkConnectedOverlay, OverlayModule, CdkOverlayOrigin} from './index'; import {OverlayContainer} from './overlay-container'; import { @@ -447,6 +447,18 @@ describe('Overlay directives', () => { expect(fixture.componentInstance.detachHandler).toHaveBeenCalled(); }); + it('should emit the keydown events from the overlay', () => { + expect(fixture.componentInstance.keydownHandler).not.toHaveBeenCalled(); + + fixture.componentInstance.isOpen = true; + fixture.detectChanges(); + + const event = dispatchKeyboardEvent(document.body, 'keydown', A); + fixture.detectChanges(); + + expect(fixture.componentInstance.keydownHandler).toHaveBeenCalledWith(event); + }); + }); }); @@ -474,6 +486,7 @@ describe('Overlay directives', () => { (positionChange)="positionChangeHandler($event)" (attach)="attachHandler()" (detach)="detachHandler()" + (overlayKeydown)="keydownHandler($event)" [cdkConnectedOverlayMinWidth]="minWidth" [cdkConnectedOverlayMinHeight]="minHeight" [cdkConnectedOverlayPositions]="positionOverrides"> @@ -499,7 +512,8 @@ class ConnectedOverlayDirectiveTest { growAfterOpen: boolean; push: boolean; backdropClickHandler = jasmine.createSpy('backdropClick handler'); - positionChangeHandler = jasmine.createSpy('positionChangeHandler'); + positionChangeHandler = jasmine.createSpy('positionChange handler'); + keydownHandler = jasmine.createSpy('keydown handler'); positionOverrides: ConnectionPositionPair[]; attachHandler = jasmine.createSpy('attachHandler').and.callFake(() => { this.attachResult = diff --git a/src/cdk/overlay/overlay-directives.ts b/src/cdk/overlay/overlay-directives.ts index 1337da06dea..da50ed72485 100644 --- a/src/cdk/overlay/overlay-directives.ts +++ b/src/cdk/overlay/overlay-directives.ts @@ -205,6 +205,9 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { /** Event emitted when the overlay has been detached. */ @Output() detach = new EventEmitter(); + /** Emits when there are keyboard events that are targeted at the overlay. */ + @Output() overlayKeydown = new EventEmitter(); + // TODO(jelbourn): inputs for size, scroll behavior, animation, etc. constructor( @@ -335,6 +338,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges { this._createOverlay(); this._overlayRef!.keydownEvents().subscribe((event: KeyboardEvent) => { + this.overlayKeydown.next(event); + if (event.keyCode === ESCAPE) { this._detachOverlay(); }