@@ -138,7 +138,7 @@ export class Dialog implements OnDestroy {
138
138
}
139
139
140
140
( this . openDialogs as DialogRef < R , C > [ ] ) . push ( dialogRef ) ;
141
- dialogRef . closed . subscribe ( ( ) => this . _removeOpenDialog ( dialogRef ) ) ;
141
+ dialogRef . closed . subscribe ( ( ) => this . _removeOpenDialog ( dialogRef , true ) ) ;
142
142
this . afterOpened . next ( dialogRef ) ;
143
143
144
144
return dialogRef ;
@@ -148,7 +148,7 @@ export class Dialog implements OnDestroy {
148
148
* Closes all of the currently-open dialogs.
149
149
*/
150
150
closeAll ( ) : void {
151
- this . _closeDialogs ( this . openDialogs ) ;
151
+ reverseForEach ( this . openDialogs , dialog => dialog . close ( ) ) ;
152
152
}
153
153
154
154
/**
@@ -160,11 +160,24 @@ export class Dialog implements OnDestroy {
160
160
}
161
161
162
162
ngOnDestroy ( ) {
163
- // Only close the dialogs at this level on destroy
164
- // since the parent service may still be active.
165
- this . _closeDialogs ( this . _openDialogsAtThisLevel ) ;
163
+ // Make one pass over all the dialogs that need to be untracked, but should not be closed. We
164
+ // want to stop tracking the open dialog even if it hasn't been closed, because the tracking
165
+ // determines when `aria-hidden` is removed from elements outside the dialog.
166
+ reverseForEach ( this . _openDialogsAtThisLevel , dialog => {
167
+ // Check for `false` specifically since we want `undefined` to be interpreted as `true`.
168
+ if ( dialog . config . closeOnDestroy === false ) {
169
+ this . _removeOpenDialog ( dialog , false ) ;
170
+ }
171
+ } ) ;
172
+
173
+ // Make a second pass and close the remaining dialogs. We do this second pass in order to
174
+ // correctly dispatch the `afterAllClosed` event in case we have a mixed array of dialogs
175
+ // that should be closed and dialogs that should not.
176
+ reverseForEach ( this . _openDialogsAtThisLevel , dialog => dialog . close ( ) ) ;
177
+
166
178
this . _afterAllClosedAtThisLevel . complete ( ) ;
167
179
this . _afterOpenedAtThisLevel . complete ( ) ;
180
+ this . _openDialogsAtThisLevel = [ ] ;
168
181
}
169
182
170
183
/**
@@ -326,8 +339,9 @@ export class Dialog implements OnDestroy {
326
339
/**
327
340
* Removes a dialog from the array of open dialogs.
328
341
* @param dialogRef Dialog to be removed.
342
+ * @param emitEvent Whether to emit an event if this is the last dialog.
329
343
*/
330
- private _removeOpenDialog < R , C > ( dialogRef : DialogRef < R , C > ) {
344
+ private _removeOpenDialog < R , C > ( dialogRef : DialogRef < R , C > , emitEvent : boolean ) {
331
345
const index = this . openDialogs . indexOf ( dialogRef ) ;
332
346
333
347
if ( index > - 1 ) {
@@ -345,7 +359,10 @@ export class Dialog implements OnDestroy {
345
359
} ) ;
346
360
347
361
this . _ariaHiddenElements . clear ( ) ;
348
- this . _getAfterAllClosed ( ) . next ( ) ;
362
+
363
+ if ( emitEvent ) {
364
+ this . _getAfterAllClosed ( ) . next ( ) ;
365
+ }
349
366
}
350
367
}
351
368
}
@@ -374,21 +391,20 @@ export class Dialog implements OnDestroy {
374
391
}
375
392
}
376
393
377
- /** Closes all of the dialogs in an array. */
378
- private _closeDialogs ( dialogs : readonly DialogRef < unknown > [ ] ) {
379
- let i = dialogs . length ;
380
-
381
- while ( i -- ) {
382
- // The `_openDialogs` property isn't updated after close until the rxjs subscription
383
- // runs on the next microtask, in addition to modifying the array as we're going
384
- // through it. We loop through all of them and call close without assuming that
385
- // they'll be removed from the list instantaneously.
386
- dialogs [ i ] . close ( ) ;
387
- }
388
- }
389
-
390
394
private _getAfterAllClosed ( ) : Subject < void > {
391
395
const parent = this . _parentDialog ;
392
396
return parent ? parent . _getAfterAllClosed ( ) : this . _afterAllClosedAtThisLevel ;
393
397
}
394
398
}
399
+
400
+ /**
401
+ * Executes a callback against all elements in an array while iterating in reverse.
402
+ * Useful if the array is being modified as it is being iterated.
403
+ */
404
+ function reverseForEach < T > ( items : T [ ] | readonly T [ ] , callback : ( current : T ) => void ) {
405
+ let i = items . length ;
406
+
407
+ while ( i -- ) {
408
+ callback ( items [ i ] ) ;
409
+ }
410
+ }
0 commit comments