@@ -38,6 +38,8 @@ import {MdDialogConfig} from './dialog-config';
38
38
import { MdDialogRef } from './dialog-ref' ;
39
39
import { MdDialogContainer } from './dialog-container' ;
40
40
import { TemplatePortal } from '../core/portal/portal' ;
41
+ import { defer } from 'rxjs/observable/defer' ;
42
+ import { startWith } from '../core/rxjs/index' ;
41
43
42
44
export const MD_DIALOG_DATA = new InjectionToken < any > ( 'MdDialogData' ) ;
43
45
@@ -70,26 +72,27 @@ export class MdDialog {
70
72
private _boundKeydown = this . _handleKeydown . bind ( this ) ;
71
73
72
74
/** 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 ;
75
77
}
76
78
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 ;
80
82
}
81
83
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 ;
86
87
}
87
88
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 ) ) ;
93
96
94
97
constructor (
95
98
private _overlay : Overlay ,
@@ -116,7 +119,7 @@ export class MdDialog {
116
119
open < T > ( componentOrTemplateRef : ComponentType < T > | TemplateRef < T > ,
117
120
config ?: MdDialogConfig ) : MdDialogRef < T > {
118
121
119
- const inProgressDialog = this . _openDialogs . find ( dialog => dialog . _isAnimating ( ) ) ;
122
+ const inProgressDialog = this . openDialogs . find ( dialog => dialog . _isAnimating ( ) ) ;
120
123
121
124
// If there's a dialog that is in the process of being opened, return it instead.
122
125
if ( inProgressDialog ) {
@@ -125,18 +128,22 @@ export class MdDialog {
125
128
126
129
config = _applyConfigDefaults ( config ) ;
127
130
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
+
128
135
const overlayRef = this . _createOverlay ( config ) ;
129
136
const dialogContainer = this . _attachDialogContainer ( overlayRef , config ) ;
130
137
const dialogRef =
131
138
this . _attachDialogContent ( componentOrTemplateRef , dialogContainer , overlayRef , config ) ;
132
139
133
- if ( ! this . _openDialogs . length ) {
140
+ if ( ! this . openDialogs . length ) {
134
141
document . addEventListener ( 'keydown' , this . _boundKeydown ) ;
135
142
}
136
143
137
- this . _openDialogs . push ( dialogRef ) ;
144
+ this . openDialogs . push ( dialogRef ) ;
138
145
dialogRef . afterClosed ( ) . subscribe ( ( ) => this . _removeOpenDialog ( dialogRef ) ) ;
139
- this . _afterOpen . next ( dialogRef ) ;
146
+ this . afterOpen . next ( dialogRef ) ;
140
147
141
148
return dialogRef ;
142
149
}
@@ -145,24 +152,32 @@ export class MdDialog {
145
152
* Closes all of the currently-open dialogs.
146
153
*/
147
154
closeAll ( ) : void {
148
- let i = this . _openDialogs . length ;
155
+ let i = this . openDialogs . length ;
149
156
150
157
while ( i -- ) {
151
158
// The `_openDialogs` property isn't updated after close until the rxjs subscription
152
159
// runs on the next microtask, in addition to modifying the array as we're going
153
160
// through it. We loop through all of them and call close without assuming that
154
161
// they'll be removed from the list instantaneously.
155
- this . _openDialogs [ i ] . close ( ) ;
162
+ this . openDialogs [ i ] . close ( ) ;
156
163
}
157
164
}
158
165
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
+
159
174
/**
160
175
* Creates the overlay into which the dialog will be loaded.
161
176
* @param config The dialog configuration.
162
177
* @returns A promise resolving to the OverlayRef for the created overlay.
163
178
*/
164
179
private _createOverlay ( config : MdDialogConfig ) : OverlayRef {
165
- let overlayState = this . _getOverlayState ( config ) ;
180
+ const overlayState = this . _getOverlayState ( config ) ;
166
181
return this . _overlay . create ( overlayState ) ;
167
182
}
168
183
@@ -172,7 +187,7 @@ export class MdDialog {
172
187
* @returns The overlay configuration.
173
188
*/
174
189
private _getOverlayState ( dialogConfig : MdDialogConfig ) : OverlayState {
175
- let overlayState = new OverlayState ( ) ;
190
+ const overlayState = new OverlayState ( ) ;
176
191
overlayState . panelClass = dialogConfig . panelClass ;
177
192
overlayState . hasBackdrop = dialogConfig . hasBackdrop ;
178
193
overlayState . scrollStrategy = this . _scrollStrategy ( ) ;
@@ -216,7 +231,7 @@ export class MdDialog {
216
231
217
232
// Create a reference to the dialog we're creating in order to give the user a handle
218
233
// to modify and close it.
219
- let dialogRef = new MdDialogRef < T > ( overlayRef , dialogContainer ) ;
234
+ const dialogRef = new MdDialogRef < T > ( overlayRef , dialogContainer , config . id ) ;
220
235
221
236
// When the dialog backdrop is clicked, we want to close it.
222
237
if ( config . hasBackdrop ) {
@@ -230,8 +245,8 @@ export class MdDialog {
230
245
if ( componentOrTemplateRef instanceof TemplateRef ) {
231
246
dialogContainer . attachTemplatePortal ( new TemplatePortal ( componentOrTemplateRef , null ! ) ) ;
232
247
} 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 (
235
250
new ComponentPortal ( componentOrTemplateRef , undefined , injector ) ) ;
236
251
dialogRef . componentInstance = contentRef . instance ;
237
252
}
@@ -256,8 +271,8 @@ export class MdDialog {
256
271
dialogRef : MdDialogRef < T > ,
257
272
dialogContainer : MdDialogContainer ) : PortalInjector {
258
273
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 ( ) ;
261
276
262
277
injectionTokens . set ( MdDialogRef , dialogRef ) ;
263
278
injectionTokens . set ( MdDialogContainer , dialogContainer ) ;
@@ -271,13 +286,13 @@ export class MdDialog {
271
286
* @param dialogRef Dialog to be removed.
272
287
*/
273
288
private _removeOpenDialog ( dialogRef : MdDialogRef < any > ) {
274
- let index = this . _openDialogs . indexOf ( dialogRef ) ;
289
+ const index = this . openDialogs . indexOf ( dialogRef ) ;
275
290
276
291
if ( index > - 1 ) {
277
- this . _openDialogs . splice ( index , 1 ) ;
292
+ this . openDialogs . splice ( index , 1 ) ;
278
293
279
294
// no open dialogs are left, call next on afterAllClosed Subject
280
- if ( ! this . _openDialogs . length ) {
295
+ if ( ! this . openDialogs . length ) {
281
296
this . _afterAllClosed . next ( ) ;
282
297
document . removeEventListener ( 'keydown' , this . _boundKeydown ) ;
283
298
}
@@ -289,8 +304,8 @@ export class MdDialog {
289
304
* top dialog when the user presses escape.
290
305
*/
291
306
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 ;
294
309
295
310
if ( event . keyCode === ESCAPE && canClose ) {
296
311
topDialog . close ( ) ;
0 commit comments