diff --git a/src/lib/dialog/dialog-config.ts b/src/lib/dialog/dialog-config.ts index 79d898938f8c..f965a693e471 100644 --- a/src/lib/dialog/dialog-config.ts +++ b/src/lib/dialog/dialog-config.ts @@ -94,5 +94,8 @@ export class MatDialogConfig { /** Whether the dialog should focus the first focusable element on open. */ autoFocus?: boolean = true; + /** Whether the dialog should close when the user goes backwards/forwards in history. */ + closeOnNavigation?: boolean = true; + // TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling. } diff --git a/src/lib/dialog/dialog-ref.ts b/src/lib/dialog/dialog-ref.ts index eca66383beb9..164b831475af 100644 --- a/src/lib/dialog/dialog-ref.ts +++ b/src/lib/dialog/dialog-ref.ts @@ -7,11 +7,13 @@ */ import {OverlayRef, GlobalPositionStrategy} from '@angular/cdk/overlay'; +import {Location} from '@angular/common'; import {filter} from 'rxjs/operators/filter'; import {take} from 'rxjs/operators/take'; import {DialogPosition} from './dialog-config'; import {Observable} from 'rxjs/Observable'; import {Subject} from 'rxjs/Subject'; +import {Subscription, ISubscription} from 'rxjs/Subscription'; import {MatDialogContainer} from './dialog-container'; @@ -42,9 +44,13 @@ export class MatDialogRef { /** Result to be passed to afterClosed. */ private _result: R | undefined; + /** Subscription to changes in the user's location. */ + private _locationChanges: ISubscription = Subscription.EMPTY; + constructor( private _overlayRef: OverlayRef, private _containerInstance: MatDialogContainer, + location?: Location, readonly id: string = `mat-dialog-${uniqueId++}`) { // Emit when opening animation completes @@ -64,10 +70,22 @@ export class MatDialogRef { ) .subscribe(() => { this._overlayRef.dispose(); + this._locationChanges.unsubscribe(); this._afterClosed.next(this._result); this._afterClosed.complete(); this.componentInstance = null!; }); + + if (location) { + // Close the dialog when the user goes forwards/backwards in history or when the location + // hash changes. Note that this usually doesn't include clicking on links (unless the user + // is using the `HashLocationStrategy`). + this._locationChanges = location.subscribe(() => { + if (this._containerInstance._config.closeOnNavigation) { + this.close(); + } + }); + } } /** diff --git a/src/lib/dialog/dialog.spec.ts b/src/lib/dialog/dialog.spec.ts index 100ce79b9417..99024c72a77d 100644 --- a/src/lib/dialog/dialog.spec.ts +++ b/src/lib/dialog/dialog.spec.ts @@ -576,6 +576,19 @@ describe('MatDialog', () => { expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(0); })); + it('should allow the consumer to disable closing a dialog on navigation', fakeAsync(() => { + dialog.open(PizzaMsg); + dialog.open(PizzaMsg, {closeOnNavigation: false}); + + expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(2); + + mockLocation.simulateUrlPop(''); + viewContainerFixture.detectChanges(); + flush(); + + expect(overlayContainerElement.querySelectorAll('mat-dialog-container').length).toBe(1); + })); + it('should have the componentInstance available in the afterClosed callback', fakeAsync(() => { let dialogRef = dialog.open(PizzaMsg); let spy = jasmine.createSpy('afterClosed spy'); diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index ab9c92fe46ce..8fd79b32ec44 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -94,17 +94,9 @@ export class MatDialog { constructor( private _overlay: Overlay, private _injector: Injector, - @Optional() location: Location, + @Optional() private _location: Location, @Inject(MAT_DIALOG_SCROLL_STRATEGY) private _scrollStrategy, - @Optional() @SkipSelf() private _parentDialog: MatDialog) { - - // Close all of the dialogs when the user goes forwards/backwards in history or when the - // location hash changes. Note that this usually doesn't include clicking on links (unless - // the user is using the `HashLocationStrategy`). - if (!_parentDialog && location) { - location.subscribe(() => this.closeAll()); - } - } + @Optional() @SkipSelf() private _parentDialog: MatDialog) { } /** * Opens a modal dialog containing the given component. @@ -223,7 +215,7 @@ export class MatDialog { // Create a reference to the dialog we're creating in order to give the user a handle // to modify and close it. - const dialogRef = new MatDialogRef(overlayRef, dialogContainer, config.id); + const dialogRef = new MatDialogRef(overlayRef, dialogContainer, this._location, config.id); // When the dialog backdrop is clicked, we want to close it. if (config.hasBackdrop) {