Skip to content

Commit 85bc3a6

Browse files
crisbetommalerba
authored andcommitted
fix(dialog): close all dialogs on popstate/hashchange (#2742)
Closes all of the open dialogs when the user goes forwards/backwards in history. Fixes #2601.
1 parent 115e901 commit 85bc3a6

File tree

3 files changed

+50
-4
lines changed

3 files changed

+50
-4
lines changed

src/lib/dialog/dialog.spec.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
} from '@angular/core';
1919
import {By} from '@angular/platform-browser';
2020
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
21+
import {Location} from '@angular/common';
22+
import {SpyLocation} from '@angular/common/testing';
2123
import {MdDialogModule} from './index';
2224
import {MdDialog} from './dialog';
2325
import {MdDialogContainer} from './dialog-container';
@@ -33,6 +35,7 @@ describe('MdDialog', () => {
3335

3436
let testViewContainerRef: ViewContainerRef;
3537
let viewContainerFixture: ComponentFixture<ComponentWithChildViewContainer>;
38+
let mockLocation: SpyLocation;
3639

3740
beforeEach(async(() => {
3841
TestBed.configureTestingModule({
@@ -41,15 +44,17 @@ describe('MdDialog', () => {
4144
{provide: OverlayContainer, useFactory: () => {
4245
overlayContainerElement = document.createElement('div');
4346
return {getContainerElement: () => overlayContainerElement};
44-
}}
47+
}},
48+
{provide: Location, useClass: SpyLocation}
4549
],
4650
});
4751

4852
TestBed.compileComponents();
4953
}));
5054

51-
beforeEach(inject([MdDialog], (d: MdDialog) => {
55+
beforeEach(inject([MdDialog, Location], (d: MdDialog, l: Location) => {
5256
dialog = d;
57+
mockLocation = l as SpyLocation;
5358
}));
5459

5560
beforeEach(() => {
@@ -334,6 +339,34 @@ describe('MdDialog', () => {
334339
expect(dialogContainer._state).toBe('exit');
335340
});
336341

342+
it('should close all dialogs when the user goes forwards/backwards in history', async(() => {
343+
dialog.open(PizzaMsg);
344+
dialog.open(PizzaMsg);
345+
346+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(2);
347+
348+
mockLocation.simulateUrlPop('');
349+
viewContainerFixture.detectChanges();
350+
351+
viewContainerFixture.whenStable().then(() => {
352+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
353+
});
354+
}));
355+
356+
it('should close all open dialogs when the location hash changes', async(() => {
357+
dialog.open(PizzaMsg);
358+
dialog.open(PizzaMsg);
359+
360+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(2);
361+
362+
mockLocation.simulateHashChange('');
363+
viewContainerFixture.detectChanges();
364+
365+
viewContainerFixture.whenStable().then(() => {
366+
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
367+
});
368+
}));
369+
337370
describe('passing in data', () => {
338371
it('should be able to pass in data', () => {
339372
let config = {
@@ -588,7 +621,8 @@ describe('MdDialog with a parent MdDialog', () => {
588621
{provide: OverlayContainer, useFactory: () => {
589622
overlayContainerElement = document.createElement('div');
590623
return {getContainerElement: () => overlayContainerElement};
591-
}}
624+
}},
625+
{provide: Location, useClass: SpyLocation}
592626
],
593627
});
594628

src/lib/dialog/dialog.ts

Lines changed: 11 additions & 1 deletion
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';
@@ -47,7 +48,16 @@ export class MdDialog {
4748
constructor(
4849
private _overlay: Overlay,
4950
private _injector: Injector,
50-
@Optional() @SkipSelf() private _parentDialog: MdDialog) { }
51+
@Optional() private _location: Location,
52+
@Optional() @SkipSelf() private _parentDialog: MdDialog) {
53+
54+
// Close all of the dialogs when the user goes forwards/backwards in history or when the
55+
// location hash changes. Note that this usually doesn't include clicking on links (unless
56+
// the user is using the `HashLocationStrategy`).
57+
if (!_parentDialog && _location) {
58+
_location.subscribe(() => this.closeAll());
59+
}
60+
}
5161

5262
/**
5363
* Opens a modal dialog containing the given component.

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)