Skip to content

Commit 23ab152

Browse files
thomaspinkandrewseguin
authored andcommitted
feat(dialog): add events (observables) for open & closeAll (#2522)
* added afterOpen & afterAllClosed observables to NgDialog + tests + demo * typo * fixed demo for aot * removed unused src argument in dialog demo * added viewContainerRef to dialog open tests * reworked dialog closeAll & open events based on feedback * added comment to change commit to the right username * added types for afterOpen & afterAllClosed * _afterAllClosed and _afterOpen subjects now delegate to state of parentDialog & removed spaces from inside import braces * fixed tslint error in dialog.ts
1 parent 6d0c40c commit 23ab152

File tree

4 files changed

+110
-3
lines changed

4 files changed

+110
-3
lines changed

src/demo-app/demo-app-module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {MaterialModule, OverlayContainer,
88
FullscreenOverlayContainer} from '@angular/material';
99
import {DEMO_APP_ROUTES} from './demo-app/routes';
1010
import {ProgressBarDemo} from './progress-bar/progress-bar-demo';
11-
import {JazzDialog, ContentElementDialog, DialogDemo} from './dialog/dialog-demo';
11+
import {JazzDialog, ContentElementDialog, DialogDemo, IFrameDialog} from './dialog/dialog-demo';
1212
import {RippleDemo} from './ripple/ripple-demo';
1313
import {IconDemo} from './icon/icon-demo';
1414
import {GesturesDemo} from './gestures/gestures-demo';
@@ -65,6 +65,7 @@ import {InputContainerDemo} from './input/input-container-demo';
6565
InputContainerDemo,
6666
JazzDialog,
6767
ContentElementDialog,
68+
IFrameDialog,
6869
ListDemo,
6970
LiveAnnouncerDemo,
7071
MdCheckboxDemoNestedChecklist,
@@ -100,6 +101,7 @@ import {InputContainerDemo} from './input/input-container-demo';
100101
DemoApp,
101102
JazzDialog,
102103
ContentElementDialog,
104+
IFrameDialog,
103105
RotiniPanel,
104106
ScienceJoke,
105107
SpagettiPanel,

src/demo-app/dialog/dialog-demo.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {Component} from '@angular/core';
1+
import {Component, Inject} from '@angular/core';
2+
import {DOCUMENT} from '@angular/platform-browser';
23
import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
34

45
@Component({
@@ -23,7 +24,19 @@ export class DialogDemo {
2324
}
2425
};
2526

26-
constructor(public dialog: MdDialog) { }
27+
constructor(public dialog: MdDialog, @Inject(DOCUMENT) doc: any) {
28+
// Possible useful example for the open and closeAll events.
29+
// Adding a class to the body if a dialog opens and
30+
// removing it after all open dialogs are closed
31+
dialog.afterOpen.subscribe((ref: MdDialogRef<any>) => {
32+
if (!doc.body.classList.contains('no-scroll')) {
33+
doc.body.classList.add('no-scroll');
34+
}
35+
});
36+
dialog.afterAllClosed.subscribe(() => {
37+
doc.body.classList.remove('no-scroll');
38+
});
39+
}
2740

2841
openJazz() {
2942
this.dialogRef = this.dialog.open(JazzDialog, this.config);
@@ -91,9 +104,46 @@ export class JazzDialog {
91104
color="primary"
92105
href="https://en.wikipedia.org/wiki/Neptune"
93106
target="_blank">Read more on Wikipedia</a>
107+
108+
<button
109+
md-button
110+
color="secondary"
111+
(click)="showInStackedDialog()">
112+
Show in Dialog</button>
94113
</md-dialog-actions>
95114
`
96115
})
97116
export class ContentElementDialog {
98117
actionsAlignment: string;
118+
119+
constructor(public dialog: MdDialog) { }
120+
121+
showInStackedDialog() {
122+
this.dialog.open(IFrameDialog);
123+
}
124+
}
125+
126+
@Component({
127+
selector: 'demo-iframe-dialog',
128+
styles: [
129+
`iframe {
130+
width: 800px;
131+
}`
132+
],
133+
template: `
134+
<h2 md-dialog-title>Neptune</h2>
135+
136+
<md-dialog-content>
137+
<iframe frameborder="0" src="https://en.wikipedia.org/wiki/Neptune"></iframe>
138+
</md-dialog-content>
139+
140+
<md-dialog-actions>
141+
<button
142+
md-raised-button
143+
color="primary"
144+
md-dialog-close>Close</button>
145+
</md-dialog-actions>
146+
`
147+
})
148+
export class IFrameDialog {
99149
}

src/lib/dialog/dialog.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,35 @@ describe('MdDialog', () => {
150150
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeFalsy();
151151
});
152152

153+
it('should notify the observers if a dialog has been opened', () => {
154+
let ref: MdDialogRef<PizzaMsg>;
155+
dialog.afterOpen.subscribe(r => {
156+
ref = r;
157+
});
158+
expect(dialog.open(PizzaMsg, {
159+
viewContainerRef: testViewContainerRef
160+
})).toBe(ref);
161+
});
162+
163+
it('should notify the observers if all open dialogs have finished closing', () => {
164+
const ref1 = dialog.open(PizzaMsg, {
165+
viewContainerRef: testViewContainerRef
166+
});
167+
const ref2 = dialog.open(ContentElementDialog, {
168+
viewContainerRef: testViewContainerRef
169+
});
170+
let allClosed = false;
171+
172+
dialog.afterAllClosed.subscribe(() => {
173+
allClosed = true;
174+
});
175+
176+
ref1.close();
177+
expect(allClosed).toBeFalsy();
178+
ref2.close();
179+
expect(allClosed).toBeTruthy();
180+
});
181+
153182
it('should should override the width of the overlay pane', () => {
154183
dialog.open(PizzaMsg, {
155184
width: '500px'

src/lib/dialog/dialog.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import {Injector, ComponentRef, Injectable, Optional, SkipSelf} from '@angular/core';
2+
import {Observable} from 'rxjs/Observable';
3+
import {Subject} from 'rxjs/Subject';
24

35
import {Overlay, OverlayRef, ComponentType, OverlayState, ComponentPortal} from '../core';
46
import {extendObject} from '../core/util/object-extend';
@@ -20,12 +22,30 @@ import {MdDialogContainer} from './dialog-container';
2022
@Injectable()
2123
export class MdDialog {
2224
private _openDialogsAtThisLevel: MdDialogRef<any>[] = [];
25+
private _afterAllClosedAtThisLevel = new Subject<void>();
26+
private _afterOpenAtThisLevel = new Subject<MdDialogRef<any>>();
2327

2428
/** Keeps track of the currently-open dialogs. */
2529
get _openDialogs(): MdDialogRef<any>[] {
2630
return this._parentDialog ? this._parentDialog._openDialogs : this._openDialogsAtThisLevel;
2731
}
2832

33+
/** Subject for notifying the user that all open dialogs have finished closing. */
34+
get _afterOpen(): Subject<MdDialogRef<any>> {
35+
return this._parentDialog ? this._parentDialog._afterOpen : this._afterOpenAtThisLevel;
36+
}
37+
/** Subject for notifying the user that a dialog has opened. */
38+
get _afterAllClosed(): Subject<void> {
39+
return this._parentDialog ?
40+
this._parentDialog._afterAllClosed : this._afterAllClosedAtThisLevel;
41+
}
42+
43+
/** Gets an observable that is notified when a dialog has been opened. */
44+
afterOpen: Observable<MdDialogRef<any>> = this._afterOpen.asObservable();
45+
46+
/** Gets an observable that is notified when all open dialog have finished closing. */
47+
afterAllClosed: Observable<void> = this._afterAllClosed.asObservable();
48+
2949
constructor(
3050
private _overlay: Overlay,
3151
private _injector: Injector,
@@ -46,6 +66,7 @@ export class MdDialog {
4666

4767
this._openDialogs.push(dialogRef);
4868
dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef));
69+
this._afterOpen.next(dialogRef);
4970

5071
return dialogRef;
5172
}
@@ -169,6 +190,11 @@ export class MdDialog {
169190

170191
if (index > -1) {
171192
this._openDialogs.splice(index, 1);
193+
194+
// no open dialogs are left, call next on afterAllClosed Subject
195+
if (!this._openDialogs.length) {
196+
this._afterAllClosed.next();
197+
}
172198
}
173199
}
174200
}

0 commit comments

Comments
 (0)