From 6d21a280ad5835833bd5011a4841fd37e3933bf9 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Tue, 22 Nov 2016 21:58:22 +0100 Subject: [PATCH] feat(dialog): add the ability to close all dialogs Adds a `closeAll` method that closes all of the currently-open dialogs. --- src/lib/dialog/README.md | 1 + src/lib/dialog/dialog.spec.ts | 12 ++++++++++++ src/lib/dialog/dialog.ts | 36 +++++++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/lib/dialog/README.md b/src/lib/dialog/README.md index b9fb3c3c1506..d68f89f54aff 100644 --- a/src/lib/dialog/README.md +++ b/src/lib/dialog/README.md @@ -7,6 +7,7 @@ MdDialog is a service, which opens dialogs components in the view. | Name | Description | | --- | --- | | `open(component: ComponentType, config: MdDialogConfig): MdDialogRef` | Creates and opens a dialog matching material spec. | +| `closeAll(): void` | Closes all of the dialogs that are currently open. | ### Config diff --git a/src/lib/dialog/dialog.spec.ts b/src/lib/dialog/dialog.spec.ts index 6d2a43466ded..2c48682eb47b 100644 --- a/src/lib/dialog/dialog.spec.ts +++ b/src/lib/dialog/dialog.spec.ts @@ -214,6 +214,18 @@ describe('MdDialog', () => { expect(overlayPane.style.right).toBe('125px'); }); + it('should close all of the dialogs', () => { + dialog.open(PizzaMsg); + dialog.open(PizzaMsg); + dialog.open(PizzaMsg); + + expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(3); + + dialog.closeAll(); + + expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0); + }); + describe('disableClose option', () => { it('should prevent closing via clicks on the backdrop', () => { dialog.open(PizzaMsg, { diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index 24cb25b8533f..d60a162af3ea 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -20,7 +20,6 @@ export {MdDialogRef} from './dialog-ref'; // TODO(jelbourn): add support for opening with a TemplateRef -// TODO(jelbourn): add `closeAll` method // TODO(jelbourn): dialog content directives (e.g., md-dialog-header) // TODO(jelbourn): animations @@ -31,6 +30,9 @@ export {MdDialogRef} from './dialog-ref'; */ @Injectable() export class MdDialog { + /** Keeps track of the currently-open dialogs. */ + private _openDialogs: MdDialogRef[] = []; + constructor(private _overlay: Overlay, private _injector: Injector) { } /** @@ -43,8 +45,27 @@ export class MdDialog { let overlayRef = this._createOverlay(config); let dialogContainer = this._attachDialogContainer(overlayRef, config); + let dialogRef = this._attachDialogContent(component, dialogContainer, overlayRef); + + this._openDialogs.push(dialogRef); + dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef)); - return this._attachDialogContent(component, dialogContainer, overlayRef); + return dialogRef; + } + + /** + * Closes all of the currently-open dialogs. + */ + closeAll(): void { + let i = this._openDialogs.length; + + while (i--) { + // The `_openDialogs` property isn't updated after close until the rxjs subscription + // runs on the next microtask, in addition to modifying the array as we're going + // through it. We loop through all of them and call close without assuming that + // they'll be removed from the list instantaneously. + this._openDialogs[i].close(); + } } /** @@ -138,6 +159,17 @@ export class MdDialog { return state; } + + /** + * Removes a dialog from the array of open dialogs. + */ + private _removeOpenDialog(dialogRef: MdDialogRef) { + let index = this._openDialogs.indexOf(dialogRef); + + if (index > -1) { + this._openDialogs.splice(index, 1); + } + } } /**