Skip to content

Commit d917bb4

Browse files
committed
feat(dialog): allow for closing on navigation to be disabled
Allows consumers to opt out of the functionality that closes all of the open dialogs when going backwards/forwards in history. Fixes #8983.
1 parent c3d7cd9 commit d917bb4

File tree

4 files changed

+37
-11
lines changed

4 files changed

+37
-11
lines changed

src/lib/dialog/dialog-config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,8 @@ export class MatDialogConfig<D = any> {
9494
/** Whether the dialog should focus the first focusable element on open. */
9595
autoFocus?: boolean = true;
9696

97+
/** Whether the dialog should close when the user goes backwards/forwards in history. */
98+
closeOnNavigation?: boolean = true;
99+
97100
// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
98101
}

src/lib/dialog/dialog-ref.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
*/
88

99
import {OverlayRef, GlobalPositionStrategy} from '@angular/cdk/overlay';
10+
import {Location} from '@angular/common';
1011
import {filter} from 'rxjs/operators/filter';
1112
import {take} from 'rxjs/operators/take';
1213
import {DialogPosition} from './dialog-config';
1314
import {Observable} from 'rxjs/Observable';
1415
import {Subject} from 'rxjs/Subject';
16+
import {Subscription, ISubscription} from 'rxjs/Subscription';
1517
import {MatDialogContainer} from './dialog-container';
1618

1719

@@ -42,9 +44,13 @@ export class MatDialogRef<T, R = any> {
4244
/** Result to be passed to afterClosed. */
4345
private _result: R | undefined;
4446

47+
/** Subscription to changes in the user's location. */
48+
private _locationChanges: ISubscription = Subscription.EMPTY;
49+
4550
constructor(
4651
private _overlayRef: OverlayRef,
4752
private _containerInstance: MatDialogContainer,
53+
location?: Location,
4854
readonly id: string = `mat-dialog-${uniqueId++}`) {
4955

5056
// Emit when opening animation completes
@@ -64,10 +70,22 @@ export class MatDialogRef<T, R = any> {
6470
)
6571
.subscribe(() => {
6672
this._overlayRef.dispose();
73+
this._locationChanges.unsubscribe();
6774
this._afterClosed.next(this._result);
6875
this._afterClosed.complete();
6976
this.componentInstance = null!;
7077
});
78+
79+
if (location) {
80+
// Close the dialog when the user goes forwards/backwards in history or when the location
81+
// hash changes. Note that this usually doesn't include clicking on links (unless the user
82+
// is using the `HashLocationStrategy`).
83+
this._locationChanges = location.subscribe(() => {
84+
if (this._containerInstance._config.closeOnNavigation) {
85+
this.close();
86+
}
87+
});
88+
}
7189
}
7290

7391
/**

src/lib/dialog/dialog.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,19 @@ describe('MatDialog', () => {
576576
expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(0);
577577
}));
578578

579+
it('should allow the consumer to disable closing a dialog on navigation', fakeAsync(() => {
580+
dialog.open(PizzaMsg);
581+
dialog.open(PizzaMsg, {closeOnNavigation: false});
582+
583+
expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(2);
584+
585+
mockLocation.simulateUrlPop('');
586+
viewContainerFixture.detectChanges();
587+
flush();
588+
589+
expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(1);
590+
}));
591+
579592
it('should have the componentInstance available in the afterClosed callback', fakeAsync(() => {
580593
let dialogRef = dialog.open(PizzaMsg);
581594
let spy = jasmine.createSpy('afterClosed spy');

src/lib/dialog/dialog.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,9 @@ export class MatDialog {
9494
constructor(
9595
private _overlay: Overlay,
9696
private _injector: Injector,
97-
@Optional() location: Location,
97+
@Optional() private _location: Location,
9898
@Inject(MAT_DIALOG_SCROLL_STRATEGY) private _scrollStrategy,
99-
@Optional() @SkipSelf() private _parentDialog: MatDialog) {
100-
101-
// Close all of the dialogs when the user goes forwards/backwards in history or when the
102-
// location hash changes. Note that this usually doesn't include clicking on links (unless
103-
// the user is using the `HashLocationStrategy`).
104-
if (!_parentDialog && location) {
105-
location.subscribe(() => this.closeAll());
106-
}
107-
}
99+
@Optional() @SkipSelf() private _parentDialog: MatDialog) { }
108100

109101
/**
110102
* Opens a modal dialog containing the given component.
@@ -223,7 +215,7 @@ export class MatDialog {
223215

224216
// Create a reference to the dialog we're creating in order to give the user a handle
225217
// to modify and close it.
226-
const dialogRef = new MatDialogRef<T>(overlayRef, dialogContainer, config.id);
218+
const dialogRef = new MatDialogRef<T>(overlayRef, dialogContainer, this._location, config.id);
227219

228220
// When the dialog backdrop is clicked, we want to close it.
229221
if (config.hasBackdrop) {

0 commit comments

Comments
 (0)