@@ -38,6 +38,8 @@ import {MdDialogConfig} from './dialog-config';
3838import { MdDialogRef } from './dialog-ref' ;
3939import { MdDialogContainer } from './dialog-container' ;
4040import { TemplatePortal } from '../core/portal/portal' ;
41+ import { defer } from 'rxjs/observable/defer' ;
42+ import { startWith } from '../core/rxjs/index' ;
4143
4244export const MD_DIALOG_DATA = new InjectionToken < any > ( 'MdDialogData' ) ;
4345
@@ -70,26 +72,27 @@ export class MdDialog {
7072 private _boundKeydown = this . _handleKeydown . bind ( this ) ;
7173
7274 /** Keeps track of the currently-open dialogs. */
73- get _openDialogs ( ) : MdDialogRef < any > [ ] {
74- return this . _parentDialog ? this . _parentDialog . _openDialogs : this . _openDialogsAtThisLevel ;
75+ get openDialogs ( ) : MdDialogRef < any > [ ] {
76+ return this . _parentDialog ? this . _parentDialog . openDialogs : this . _openDialogsAtThisLevel ;
7577 }
7678
77- /** Subject for notifying the user that a dialog has opened. */
78- get _afterOpen ( ) : Subject < MdDialogRef < any > > {
79- return this . _parentDialog ? this . _parentDialog . _afterOpen : this . _afterOpenAtThisLevel ;
79+ /** Stream that emits when a dialog has been opened. */
80+ get afterOpen ( ) : Subject < MdDialogRef < any > > {
81+ return this . _parentDialog ? this . _parentDialog . afterOpen : this . _afterOpenAtThisLevel ;
8082 }
8183
82- /** Subject for notifying the user that all open dialogs have finished closing. */
83- get _afterAllClosed ( ) : Subject < void > {
84- return this . _parentDialog ?
85- this . _parentDialog . _afterAllClosed : this . _afterAllClosedAtThisLevel ;
84+ get _afterAllClosed ( ) {
85+ const parent = this . _parentDialog ;
86+ return parent ? parent . _afterAllClosed : this . _afterAllClosedAtThisLevel ;
8687 }
8788
88- /** Gets an observable that is notified when a dialog has been opened. */
89- afterOpen : Observable < MdDialogRef < any > > = this . _afterOpen . asObservable ( ) ;
90-
91- /** Gets an observable that is notified when all open dialog have finished closing. */
92- afterAllClosed : Observable < void > = this . _afterAllClosed . asObservable ( ) ;
89+ /**
90+ * Stream that emits when all open dialog have finished closing.
91+ * Will emit on subscribe if there are no open dialogs to begin with.
92+ */
93+ afterAllClosed : Observable < void > = defer < void > ( ( ) => this . openDialogs . length ?
94+ this . _afterAllClosed :
95+ startWith . call ( this . _afterAllClosed , undefined ) ) ;
9396
9497 constructor (
9598 private _overlay : Overlay ,
@@ -116,7 +119,7 @@ export class MdDialog {
116119 open < T > ( componentOrTemplateRef : ComponentType < T > | TemplateRef < T > ,
117120 config ?: MdDialogConfig ) : MdDialogRef < T > {
118121
119- const inProgressDialog = this . _openDialogs . find ( dialog => dialog . _isAnimating ( ) ) ;
122+ const inProgressDialog = this . openDialogs . find ( dialog => dialog . _isAnimating ( ) ) ;
120123
121124 // If there's a dialog that is in the process of being opened, return it instead.
122125 if ( inProgressDialog ) {
@@ -125,18 +128,22 @@ export class MdDialog {
125128
126129 config = _applyConfigDefaults ( config ) ;
127130
131+ if ( config . id && this . getDialogById ( config . id ) ) {
132+ throw Error ( `Dialog with id "${ config . id } " exists already. The dialog id must be unique.` ) ;
133+ }
134+
128135 const overlayRef = this . _createOverlay ( config ) ;
129136 const dialogContainer = this . _attachDialogContainer ( overlayRef , config ) ;
130137 const dialogRef =
131138 this . _attachDialogContent ( componentOrTemplateRef , dialogContainer , overlayRef , config ) ;
132139
133- if ( ! this . _openDialogs . length ) {
140+ if ( ! this . openDialogs . length ) {
134141 document . addEventListener ( 'keydown' , this . _boundKeydown ) ;
135142 }
136143
137- this . _openDialogs . push ( dialogRef ) ;
144+ this . openDialogs . push ( dialogRef ) ;
138145 dialogRef . afterClosed ( ) . subscribe ( ( ) => this . _removeOpenDialog ( dialogRef ) ) ;
139- this . _afterOpen . next ( dialogRef ) ;
146+ this . afterOpen . next ( dialogRef ) ;
140147
141148 return dialogRef ;
142149 }
@@ -145,24 +152,32 @@ export class MdDialog {
145152 * Closes all of the currently-open dialogs.
146153 */
147154 closeAll ( ) : void {
148- let i = this . _openDialogs . length ;
155+ let i = this . openDialogs . length ;
149156
150157 while ( i -- ) {
151158 // The `_openDialogs` property isn't updated after close until the rxjs subscription
152159 // runs on the next microtask, in addition to modifying the array as we're going
153160 // through it. We loop through all of them and call close without assuming that
154161 // they'll be removed from the list instantaneously.
155- this . _openDialogs [ i ] . close ( ) ;
162+ this . openDialogs [ i ] . close ( ) ;
156163 }
157164 }
158165
166+ /**
167+ * Finds an open dialog by its id.
168+ * @param id ID to use when looking up the dialog.
169+ */
170+ getDialogById ( id : string ) : MdDialogRef < any > | undefined {
171+ return this . openDialogs . find ( dialog => dialog . id === id ) ;
172+ }
173+
159174 /**
160175 * Creates the overlay into which the dialog will be loaded.
161176 * @param config The dialog configuration.
162177 * @returns A promise resolving to the OverlayRef for the created overlay.
163178 */
164179 private _createOverlay ( config : MdDialogConfig ) : OverlayRef {
165- let overlayState = this . _getOverlayState ( config ) ;
180+ const overlayState = this . _getOverlayState ( config ) ;
166181 return this . _overlay . create ( overlayState ) ;
167182 }
168183
@@ -172,7 +187,7 @@ export class MdDialog {
172187 * @returns The overlay configuration.
173188 */
174189 private _getOverlayState ( dialogConfig : MdDialogConfig ) : OverlayState {
175- let overlayState = new OverlayState ( ) ;
190+ const overlayState = new OverlayState ( ) ;
176191 overlayState . panelClass = dialogConfig . panelClass ;
177192 overlayState . hasBackdrop = dialogConfig . hasBackdrop ;
178193 overlayState . scrollStrategy = this . _scrollStrategy ( ) ;
@@ -216,7 +231,7 @@ export class MdDialog {
216231
217232 // Create a reference to the dialog we're creating in order to give the user a handle
218233 // to modify and close it.
219- let dialogRef = new MdDialogRef < T > ( overlayRef , dialogContainer ) ;
234+ const dialogRef = new MdDialogRef < T > ( overlayRef , dialogContainer , config . id ) ;
220235
221236 // When the dialog backdrop is clicked, we want to close it.
222237 if ( config . hasBackdrop ) {
@@ -230,8 +245,8 @@ export class MdDialog {
230245 if ( componentOrTemplateRef instanceof TemplateRef ) {
231246 dialogContainer . attachTemplatePortal ( new TemplatePortal ( componentOrTemplateRef , null ! ) ) ;
232247 } else {
233- let injector = this . _createInjector < T > ( config , dialogRef , dialogContainer ) ;
234- let contentRef = dialogContainer . attachComponentPortal (
248+ const injector = this . _createInjector < T > ( config , dialogRef , dialogContainer ) ;
249+ const contentRef = dialogContainer . attachComponentPortal (
235250 new ComponentPortal ( componentOrTemplateRef , undefined , injector ) ) ;
236251 dialogRef . componentInstance = contentRef . instance ;
237252 }
@@ -256,8 +271,8 @@ export class MdDialog {
256271 dialogRef : MdDialogRef < T > ,
257272 dialogContainer : MdDialogContainer ) : PortalInjector {
258273
259- let userInjector = config && config . viewContainerRef && config . viewContainerRef . injector ;
260- let injectionTokens = new WeakMap ( ) ;
274+ const userInjector = config && config . viewContainerRef && config . viewContainerRef . injector ;
275+ const injectionTokens = new WeakMap ( ) ;
261276
262277 injectionTokens . set ( MdDialogRef , dialogRef ) ;
263278 injectionTokens . set ( MdDialogContainer , dialogContainer ) ;
@@ -271,13 +286,13 @@ export class MdDialog {
271286 * @param dialogRef Dialog to be removed.
272287 */
273288 private _removeOpenDialog ( dialogRef : MdDialogRef < any > ) {
274- let index = this . _openDialogs . indexOf ( dialogRef ) ;
289+ const index = this . openDialogs . indexOf ( dialogRef ) ;
275290
276291 if ( index > - 1 ) {
277- this . _openDialogs . splice ( index , 1 ) ;
292+ this . openDialogs . splice ( index , 1 ) ;
278293
279294 // no open dialogs are left, call next on afterAllClosed Subject
280- if ( ! this . _openDialogs . length ) {
295+ if ( ! this . openDialogs . length ) {
281296 this . _afterAllClosed . next ( ) ;
282297 document . removeEventListener ( 'keydown' , this . _boundKeydown ) ;
283298 }
@@ -289,8 +304,8 @@ export class MdDialog {
289304 * top dialog when the user presses escape.
290305 */
291306 private _handleKeydown ( event : KeyboardEvent ) : void {
292- let topDialog = this . _openDialogs [ this . _openDialogs . length - 1 ] ;
293- let canClose = topDialog ? ! topDialog . disableClose : false ;
307+ const topDialog = this . openDialogs [ this . openDialogs . length - 1 ] ;
308+ const canClose = topDialog ? ! topDialog . disableClose : false ;
294309
295310 if ( event . keyCode === ESCAPE && canClose ) {
296311 topDialog . close ( ) ;
0 commit comments