Skip to content

Commit 1b78613

Browse files
committed
fix(dialog): close all dialogs on popstate/hashchange
Closes all of the open dialogs when the user goes forwards/backwards in history. Fixes #2601.
1 parent b939cd8 commit 1b78613

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

src/lib/dialog/dialog.spec.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {NgModule,
1515
Injector,
1616
Inject,
1717
} from '@angular/core';
18+
import {Location} from '@angular/common';
19+
import {SpyLocation} from '@angular/common/testing';
1820
import {MdDialogModule} from './index';
1921
import {MdDialog} from './dialog';
2022
import {OverlayContainer} from '../core';
@@ -29,6 +31,7 @@ describe('MdDialog', () => {
2931

3032
let testViewContainerRef: ViewContainerRef;
3133
let viewContainerFixture: ComponentFixture<ComponentWithChildViewContainer>;
34+
let mockLocation: SpyLocation;
3235

3336
beforeEach(async(() => {
3437
TestBed.configureTestingModule({
@@ -37,15 +40,17 @@ describe('MdDialog', () => {
3740
{provide: OverlayContainer, useFactory: () => {
3841
overlayContainerElement = document.createElement('div');
3942
return {getContainerElement: () => overlayContainerElement};
40-
}}
43+
}},
44+
{provide: Location, useClass: SpyLocation}
4145
],
4246
});
4347

4448
TestBed.compileComponents();
4549
}));
4650

47-
beforeEach(inject([MdDialog], (d: MdDialog) => {
51+
beforeEach(inject([MdDialog, Location], (d: MdDialog, l: Location) => {
4852
dialog = d;
53+
mockLocation = l as SpyLocation;
4954
}));
5055

5156
beforeEach(() => {
@@ -274,6 +279,28 @@ describe('MdDialog', () => {
274279
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
275280
});
276281

282+
it('should close all open dialogs when the user goes forwards/backwards in history', () => {
283+
dialog.open(PizzaMsg);
284+
dialog.open(PizzaMsg);
285+
286+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(2);
287+
288+
mockLocation.simulateUrlPop('');
289+
290+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
291+
});
292+
293+
it('should close all open dialogs when the location hash changes', () => {
294+
dialog.open(PizzaMsg);
295+
dialog.open(PizzaMsg);
296+
297+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(2);
298+
299+
mockLocation.simulateHashChange('');
300+
301+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
302+
});
303+
277304
describe('passing in data', () => {
278305
it('should be able to pass in data', () => {
279306
let config = {
@@ -433,7 +460,8 @@ describe('MdDialog with a parent MdDialog', () => {
433460
{provide: OverlayContainer, useFactory: () => {
434461
overlayContainerElement = document.createElement('div');
435462
return {getContainerElement: () => overlayContainerElement};
436-
}}
463+
}},
464+
{provide: Location, useClass: SpyLocation}
437465
],
438466
});
439467

src/lib/dialog/dialog.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {Injector, ComponentRef, Injectable, Optional, SkipSelf, TemplateRef} from '@angular/core';
2+
import {Location} from '@angular/common';
23
import {Observable} from 'rxjs/Observable';
34
import {Subject} from 'rxjs/Subject';
45
import {Overlay, OverlayRef, ComponentType, OverlayState, ComponentPortal} from '../core';
@@ -49,7 +50,16 @@ export class MdDialog {
4950
constructor(
5051
private _overlay: Overlay,
5152
private _injector: Injector,
52-
@Optional() @SkipSelf() private _parentDialog: MdDialog) { }
53+
private _location: Location,
54+
@Optional() @SkipSelf() private _parentDialog: MdDialog) {
55+
56+
// Close all of the dialogs when the user goes forwards/backwards in history or when the
57+
// location hash changes. Note that this usually doesn't include clicking on links (unless
58+
// the user is using the `HashLocationStrategy`).
59+
if (!_parentDialog) {
60+
_location.subscribe(() => this.closeAll());
61+
}
62+
}
5363

5464
/**
5565
* Opens a modal dialog containing the given component.
@@ -135,7 +145,7 @@ export class MdDialog {
135145
config?: MdDialogConfig): MdDialogRef<T> {
136146
// Create a reference to the dialog we're creating in order to give the user a handle
137147
// to modify and close it.
138-
let dialogRef = <MdDialogRef<T>> new MdDialogRef(overlayRef, config);
148+
let dialogRef = new MdDialogRef(overlayRef, config) as MdDialogRef<T>;
139149

140150
if (!config.disableClose) {
141151
// When the dialog backdrop is clicked, we want to close it.

src/lib/dialog/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {NgModule, ModuleWithProviders} from '@angular/core';
2+
import {CommonModule} from '@angular/common';
23
import {
34
OverlayModule,
45
PortalModule,
@@ -17,6 +18,7 @@ import {
1718

1819
@NgModule({
1920
imports: [
21+
CommonModule,
2022
OverlayModule,
2123
PortalModule,
2224
A11yModule,

0 commit comments

Comments
 (0)