From b061da0202ee49dd3e8b83d89bc3172b5ce40331 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Fri, 29 Jun 2018 18:16:54 +0200 Subject: [PATCH] feat(overlay): expose keydown events on the opened overlay 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 3c57df929108..875a0a16ecc2 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 1337da06dea1..da50ed72485c 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(); }