diff --git a/src/lib/dialog/dialog-config.ts b/src/lib/dialog/dialog-config.ts index 3a14b8daa879..414be208777f 100644 --- a/src/lib/dialog/dialog-config.ts +++ b/src/lib/dialog/dialog-config.ts @@ -98,5 +98,8 @@ export class MatDialogConfig { /** Scroll strategy to be used for the dialog. */ scrollStrategy?: ScrollStrategy; + /** 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 bba90abf060b..b07addf2c726 100644 --- a/src/lib/dialog/dialog-ref.ts +++ b/src/lib/dialog/dialog-ref.ts @@ -8,11 +8,13 @@ import {OverlayRef, GlobalPositionStrategy} from '@angular/cdk/overlay'; import {ESCAPE} from '@angular/cdk/keycodes'; +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'; @@ -43,9 +45,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 @@ -65,6 +71,7 @@ export class MatDialogRef { ) .subscribe(() => { this._overlayRef.dispose(); + this._locationChanges.unsubscribe(); this._afterClosed.next(this._result); this._afterClosed.complete(); this.componentInstance = null!; @@ -73,6 +80,17 @@ export class MatDialogRef { _overlayRef.keydownEvents() .pipe(filter(event => event.keyCode === ESCAPE && !this.disableClose)) .subscribe(() => this.close()); + + 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 7265e483db0c..51b615e92707 100644 --- a/src/lib/dialog/dialog.spec.ts +++ b/src/lib/dialog/dialog.spec.ts @@ -582,6 +582,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 ed72c21e568c..e9d6335832e8 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -96,19 +96,11 @@ export class MatDialog { constructor( private _overlay: Overlay, private _injector: Injector, - @Optional() location: Location, + @Optional() private _location: Location, @Optional() @Inject(MAT_DIALOG_DEFAULT_OPTIONS) private _defaultOptions, @Inject(MAT_DIALOG_SCROLL_STRATEGY) private _scrollStrategy, @Optional() @SkipSelf() private _parentDialog: MatDialog, - private _overlayContainer: OverlayContainer) { - - // 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()); - } - } + private _overlayContainer: OverlayContainer) {} /** * Opens a modal dialog containing the given component. @@ -232,7 +224,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) {