@@ -138,7 +138,7 @@ export class Dialog implements OnDestroy {
138138 }
139139
140140 ( this . openDialogs as DialogRef < R , C > [ ] ) . push ( dialogRef ) ;
141- dialogRef . closed . subscribe ( ( ) => this . _removeOpenDialog ( dialogRef ) ) ;
141+ dialogRef . closed . subscribe ( ( ) => this . _removeOpenDialog ( dialogRef , true ) ) ;
142142 this . afterOpened . next ( dialogRef ) ;
143143
144144 return dialogRef ;
@@ -148,7 +148,7 @@ export class Dialog implements OnDestroy {
148148 * Closes all of the currently-open dialogs.
149149 */
150150 closeAll ( ) : void {
151- this . _closeDialogs ( this . openDialogs ) ;
151+ reverseForEach ( this . openDialogs , dialog => dialog . close ( ) ) ;
152152 }
153153
154154 /**
@@ -160,11 +160,24 @@ export class Dialog implements OnDestroy {
160160 }
161161
162162 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+
166178 this . _afterAllClosedAtThisLevel . complete ( ) ;
167179 this . _afterOpenedAtThisLevel . complete ( ) ;
180+ this . _openDialogsAtThisLevel = [ ] ;
168181 }
169182
170183 /**
@@ -326,8 +339,9 @@ export class Dialog implements OnDestroy {
326339 /**
327340 * Removes a dialog from the array of open dialogs.
328341 * @param dialogRef Dialog to be removed.
342+ * @param emitEvent Whether to emit an event if this is the last dialog.
329343 */
330- private _removeOpenDialog < R , C > ( dialogRef : DialogRef < R , C > ) {
344+ private _removeOpenDialog < R , C > ( dialogRef : DialogRef < R , C > , emitEvent : boolean ) {
331345 const index = this . openDialogs . indexOf ( dialogRef ) ;
332346
333347 if ( index > - 1 ) {
@@ -345,7 +359,10 @@ export class Dialog implements OnDestroy {
345359 } ) ;
346360
347361 this . _ariaHiddenElements . clear ( ) ;
348- this . _getAfterAllClosed ( ) . next ( ) ;
362+
363+ if ( emitEvent ) {
364+ this . _getAfterAllClosed ( ) . next ( ) ;
365+ }
349366 }
350367 }
351368 }
@@ -374,21 +391,20 @@ export class Dialog implements OnDestroy {
374391 }
375392 }
376393
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-
390394 private _getAfterAllClosed ( ) : Subject < void > {
391395 const parent = this . _parentDialog ;
392396 return parent ? parent . _getAfterAllClosed ( ) : this . _afterAllClosedAtThisLevel ;
393397 }
394398}
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