diff --git a/src/lib/dialog/dialog-container.ts b/src/lib/dialog/dialog-container.ts index cc38a229c550..5f920aa0d0ca 100644 --- a/src/lib/dialog/dialog-container.ts +++ b/src/lib/dialog/dialog-container.ts @@ -8,6 +8,7 @@ import { } from '@angular/core'; import {BasePortalHost, ComponentPortal, PortalHostDirective, TemplatePortal} from '../core'; import {MdDialogConfig} from './dialog-config'; +import {MdDialogRef} from './dialog-ref'; import {MdDialogContentAlreadyAttachedError} from './dialog-errors'; import {FocusTrap} from '../core/a11y/focus-trap'; import 'rxjs/add/operator/first'; @@ -23,7 +24,8 @@ import 'rxjs/add/operator/first'; styleUrls: ['dialog-container.css'], host: { 'class': 'md-dialog-container', - '[attr.role]': 'dialogConfig?.role' + '[attr.role]': 'dialogConfig?.role', + '(keydown.escape)': 'handleEscapeKey()', }, encapsulation: ViewEncapsulation.None, }) @@ -40,6 +42,9 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { /** The dialog configuration. */ dialogConfig: MdDialogConfig; + /** Reference to the open dialog. */ + dialogRef: MdDialogRef; + constructor(private _ngZone: NgZone) { super(); } @@ -67,6 +72,12 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { throw Error('Not yet implemented'); } + /** Handles the user pressing the Escape key. */ + handleEscapeKey() { + // TODO(jelbourn): add MdDialogConfig option to disable this behavior. + this.dialogRef.close(); + } + ngOnDestroy() { // When the dialog is destroyed, return focus to the element that originally had it before // the dialog was opened. Wait for the DOM to finish settling before changing the focus so diff --git a/src/lib/dialog/dialog.spec.ts b/src/lib/dialog/dialog.spec.ts index 432e21c675e9..6ff5b8651ee8 100644 --- a/src/lib/dialog/dialog.spec.ts +++ b/src/lib/dialog/dialog.spec.ts @@ -6,11 +6,13 @@ import { ComponentFixture, TestBed, } from '@angular/core/testing'; +import {By} from '@angular/platform-browser'; import {NgModule, Component, Directive, ViewChild, ViewContainerRef} from '@angular/core'; import {MdDialog, MdDialogModule} from './dialog'; import {OverlayContainer} from '../core'; import {MdDialogConfig} from './dialog-config'; import {MdDialogRef} from './dialog-ref'; +import {MdDialogContainer} from './dialog-container'; describe('MdDialog', () => { @@ -94,6 +96,24 @@ describe('MdDialog', () => { expect(overlayContainerElement.querySelector('md-dialog-container')).toBeNull(); }); + + it('should close a dialog via the escape key', () => { + let config = new MdDialogConfig(); + config.viewContainerRef = testViewContainerRef; + + dialog.open(PizzaMsg, config); + + viewContainerFixture.detectChanges(); + + let dialogContainer: MdDialogContainer = + viewContainerFixture.debugElement.query(By.directive(MdDialogContainer)).componentInstance; + + // Fake the user pressing the escape key by calling the handler directly. + dialogContainer.handleEscapeKey(); + + expect(overlayContainerElement.querySelector('md-dialog-container')).toBeNull(); + }); + it('should close when clicking on the overlay backdrop', () => { let config = new MdDialogConfig(); config.viewContainerRef = testViewContainerRef; diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index 8709cd6c51a3..bd4d5dc177b5 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -90,6 +90,9 @@ export class MdDialog { // When the dialog backdrop is clicked, we want to close it. overlayRef.backdropClick().subscribe(() => dialogRef.close()); + // Set the dialogRef to the container so that it can use the ref to close the dialog. + dialogContainer.dialogRef = dialogRef; + // We create an injector specifically for the component we're instantiating so that it can // inject the MdDialogRef. This allows a component loaded inside of a dialog to close itself // and, optionally, to return a value.