Skip to content

Commit

Permalink
feat(dialog): allow for closing on navigation to be disabled (#9024)
Browse files Browse the repository at this point in the history
Allows consumers to opt out of the functionality that closes all of the open dialogs when going backwards/forwards in history.

Fixes #8983.
  • Loading branch information
crisbeto authored and jelbourn committed Jan 8, 2018
1 parent 8492637 commit c349c58
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 11 deletions.
3 changes: 3 additions & 0 deletions src/lib/dialog/dialog-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,8 @@ export class MatDialogConfig<D = any> {
/** 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.
}
18 changes: 18 additions & 0 deletions src/lib/dialog/dialog-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';


Expand Down Expand Up @@ -43,9 +45,13 @@ export class MatDialogRef<T, R = any> {
/** 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
Expand All @@ -65,6 +71,7 @@ export class MatDialogRef<T, R = any> {
)
.subscribe(() => {
this._overlayRef.dispose();
this._locationChanges.unsubscribe();
this._afterClosed.next(this._result);
this._afterClosed.complete();
this.componentInstance = null!;
Expand All @@ -73,6 +80,17 @@ export class MatDialogRef<T, R = any> {
_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();
}
});
}
}

/**
Expand Down
13 changes: 13 additions & 0 deletions src/lib/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
14 changes: 3 additions & 11 deletions src/lib/dialog/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<T>(overlayRef, dialogContainer, config.id);
const dialogRef = new MatDialogRef<T>(overlayRef, dialogContainer, this._location, config.id);

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

0 comments on commit c349c58

Please sign in to comment.