Skip to content

Commit 66629cf

Browse files
crisbetoandrewseguin
authored andcommitted
feat(dialog): allow disableClose option to be updated (#4964)
* Exposes the disableClose option via the `MdDialogRef` and allows for it to be updated. * Makes the `containerInstance` private to `MdDialogRef` since it doesn't make sense for it to be public anymore. * Completes the `backdropClick` observable once the associated `overlayRef` is destroyed. This avoids having to unsubscribe manually or having to use `Observable.first`. Fixes #3938.
1 parent 657f0e8 commit 66629cf

File tree

6 files changed

+54
-10
lines changed

6 files changed

+54
-10
lines changed

src/lib/core/overlay/overlay-ref.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export class OverlayRef implements PortalHost {
100100
this.detachBackdrop();
101101
this._portalHost.dispose();
102102
this._attachments.complete();
103+
this._backdropClick.complete();
103104
this._detachments.next();
104105
this._detachments.complete();
105106
}

src/lib/core/overlay/overlay.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,21 @@ describe('Overlay', () => {
327327
expect(backdropClickHandler).toHaveBeenCalled();
328328
});
329329

330+
it('should complete the backdrop click stream once the overlay is destroyed', () => {
331+
let overlayRef = overlay.create(config);
332+
333+
overlayRef.attach(componentPortal);
334+
viewContainerFixture.detectChanges();
335+
336+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
337+
let completeHandler = jasmine.createSpy('backdrop complete handler');
338+
339+
overlayRef.backdropClick().subscribe(null, null, completeHandler);
340+
overlayRef.dispose();
341+
342+
expect(completeHandler).toHaveBeenCalled();
343+
});
344+
330345
it('should apply the default overlay backdrop class', () => {
331346
let overlayRef = overlay.create(config);
332347
overlayRef.attach(componentPortal);

src/lib/dialog/dialog-container.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function throwMdDialogContentAlreadyAttachedError() {
5757
],
5858
host: {
5959
'[class.mat-dialog-container]': 'true',
60-
'[attr.role]': 'dialogConfig?.role',
60+
'[attr.role]': 'config?.role',
6161
'[@slideDialog]': '_state',
6262
'(@slideDialog.done)': '_onAnimationDone($event)',
6363
},
@@ -76,7 +76,7 @@ export class MdDialogContainer extends BasePortalHost {
7676
private _document: Document;
7777

7878
/** The dialog configuration. */
79-
dialogConfig: MdDialogConfig;
79+
config: MdDialogConfig;
8080

8181
/** State of the dialog animation. */
8282
_state: 'void' | 'enter' | 'exit' = 'enter';

src/lib/dialog/dialog-ref.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ export class MdDialogRef<T> {
1818
/** The instance of component opened into the dialog. */
1919
componentInstance: T;
2020

21+
/** Whether the user is allowed to close the dialog. */
22+
disableClose: boolean = this._containerInstance.config.disableClose;
23+
2124
/** Subject for notifying the user that the dialog has finished closing. */
2225
private _afterClosed: Subject<any> = new Subject();
2326

2427
/** Result to be passed to afterClosed. */
2528
private _result: any;
2629

27-
constructor(private _overlayRef: OverlayRef, public _containerInstance: MdDialogContainer) {
30+
constructor(private _overlayRef: OverlayRef, private _containerInstance: MdDialogContainer) {
2831
_containerInstance._onAnimationStateChange
2932
.filter((event: AnimationEvent) => event.toState === 'exit')
3033
.subscribe(() => this._overlayRef.dispose(), null, () => {

src/lib/dialog/dialog.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,28 @@ describe('MdDialog', () => {
451451

452452
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy();
453453
});
454+
455+
it('should allow for the disableClose option to be updated while open', async(() => {
456+
let dialogRef = dialog.open(PizzaMsg, {
457+
disableClose: true,
458+
viewContainerRef: testViewContainerRef
459+
});
460+
461+
viewContainerFixture.detectChanges();
462+
463+
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
464+
backdrop.click();
465+
466+
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy();
467+
468+
dialogRef.disableClose = false;
469+
backdrop.click();
470+
471+
viewContainerFixture.detectChanges();
472+
viewContainerFixture.whenStable().then(() => {
473+
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeFalsy();
474+
});
475+
}));
454476
});
455477

456478
describe('hasBackdrop option', () => {

src/lib/dialog/dialog.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import {MdDialogConfig} from './dialog-config';
1616
import {MdDialogRef} from './dialog-ref';
1717
import {MdDialogContainer} from './dialog-container';
1818
import {TemplatePortal} from '../core/portal/portal';
19-
import 'rxjs/add/operator/first';
2019

2120

2221
/**
@@ -147,7 +146,7 @@ export class MdDialog {
147146
let containerPortal = new ComponentPortal(MdDialogContainer, viewContainer);
148147

149148
let containerRef: ComponentRef<MdDialogContainer> = overlay.attach(containerPortal);
150-
containerRef.instance.dialogConfig = config;
149+
containerRef.instance.config = config;
151150

152151
return containerRef.instance;
153152
}
@@ -166,14 +165,18 @@ export class MdDialog {
166165
dialogContainer: MdDialogContainer,
167166
overlayRef: OverlayRef,
168167
config: MdDialogConfig): MdDialogRef<T> {
168+
169169
// Create a reference to the dialog we're creating in order to give the user a handle
170170
// to modify and close it.
171-
172171
let dialogRef = new MdDialogRef<T>(overlayRef, dialogContainer);
173172

174-
if (!config.disableClose) {
175-
// When the dialog backdrop is clicked, we want to close it.
176-
overlayRef.backdropClick().first().subscribe(() => dialogRef.close());
173+
// When the dialog backdrop is clicked, we want to close it.
174+
if (config.hasBackdrop) {
175+
overlayRef.backdropClick().subscribe(() => {
176+
if (!dialogRef.disableClose) {
177+
dialogRef.close();
178+
}
179+
});
177180
}
178181

179182
// We create an injector specifically for the component we're instantiating so that it can
@@ -221,7 +224,7 @@ export class MdDialog {
221224
*/
222225
private _handleKeydown(event: KeyboardEvent): void {
223226
let topDialog = this._openDialogs[this._openDialogs.length - 1];
224-
let canClose = topDialog ? !topDialog._containerInstance.dialogConfig.disableClose : false;
227+
let canClose = topDialog ? !topDialog.disableClose : false;
225228

226229
if (event.keyCode === ESCAPE && canClose) {
227230
topDialog.close();

0 commit comments

Comments
 (0)