Skip to content

Commit

Permalink
fix(dialog): close all dialogs on popstate/hashchange (#2742)
Browse files Browse the repository at this point in the history
Closes all of the open dialogs when the user goes forwards/backwards in history.

Fixes #2601.
  • Loading branch information
crisbeto authored and mmalerba committed Apr 25, 2017
1 parent 115e901 commit 85bc3a6
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 4 deletions.
40 changes: 37 additions & 3 deletions src/lib/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
} from '@angular/core';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {Location} from '@angular/common';
import {SpyLocation} from '@angular/common/testing';
import {MdDialogModule} from './index';
import {MdDialog} from './dialog';
import {MdDialogContainer} from './dialog-container';
Expand All @@ -33,6 +35,7 @@ describe('MdDialog', () => {

let testViewContainerRef: ViewContainerRef;
let viewContainerFixture: ComponentFixture<ComponentWithChildViewContainer>;
let mockLocation: SpyLocation;

beforeEach(async(() => {
TestBed.configureTestingModule({
Expand All @@ -41,15 +44,17 @@ describe('MdDialog', () => {
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
return {getContainerElement: () => overlayContainerElement};
}}
}},
{provide: Location, useClass: SpyLocation}
],
});

TestBed.compileComponents();
}));

beforeEach(inject([MdDialog], (d: MdDialog) => {
beforeEach(inject([MdDialog, Location], (d: MdDialog, l: Location) => {
dialog = d;
mockLocation = l as SpyLocation;
}));

beforeEach(() => {
Expand Down Expand Up @@ -334,6 +339,34 @@ describe('MdDialog', () => {
expect(dialogContainer._state).toBe('exit');
});

it('should close all dialogs when the user goes forwards/backwards in history', async(() => {
dialog.open(PizzaMsg);
dialog.open(PizzaMsg);

expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(2);

mockLocation.simulateUrlPop('');
viewContainerFixture.detectChanges();

viewContainerFixture.whenStable().then(() => {
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
});
}));

it('should close all open dialogs when the location hash changes', async(() => {
dialog.open(PizzaMsg);
dialog.open(PizzaMsg);

expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(2);

mockLocation.simulateHashChange('');
viewContainerFixture.detectChanges();

viewContainerFixture.whenStable().then(() => {
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
});
}));

describe('passing in data', () => {
it('should be able to pass in data', () => {
let config = {
Expand Down Expand Up @@ -588,7 +621,8 @@ describe('MdDialog with a parent MdDialog', () => {
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
return {getContainerElement: () => overlayContainerElement};
}}
}},
{provide: Location, useClass: SpyLocation}
],
});

Expand Down
12 changes: 11 additions & 1 deletion src/lib/dialog/dialog.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Injector, ComponentRef, Injectable, Optional, SkipSelf, TemplateRef} from '@angular/core';
import {Location} from '@angular/common';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {Overlay, OverlayRef, ComponentType, OverlayState, ComponentPortal} from '../core';
Expand Down Expand Up @@ -47,7 +48,16 @@ export class MdDialog {
constructor(
private _overlay: Overlay,
private _injector: Injector,
@Optional() @SkipSelf() private _parentDialog: MdDialog) { }
@Optional() private _location: Location,
@Optional() @SkipSelf() private _parentDialog: MdDialog) {

// 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());
}
}

/**
* Opens a modal dialog containing the given component.
Expand Down
2 changes: 2 additions & 0 deletions src/lib/dialog/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
import {
OverlayModule,
PortalModule,
Expand All @@ -17,6 +18,7 @@ import {

@NgModule({
imports: [
CommonModule,
OverlayModule,
PortalModule,
A11yModule,
Expand Down

0 comments on commit 85bc3a6

Please sign in to comment.