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.
This commit is contained in:
Kristiyan Kostadinov
2017-06-08 20:22:03 +02:00
committed by Andrew Seguin
parent 657f0e829e
commit 66629cf1ed
6 changed files with 54 additions and 10 deletions
+1
View File
@@ -100,6 +100,7 @@ export class OverlayRef implements PortalHost {
this.detachBackdrop();
this._portalHost.dispose();
this._attachments.complete();
this._backdropClick.complete();
this._detachments.next();
this._detachments.complete();
}
+15
View File
@@ -327,6 +327,21 @@ describe('Overlay', () => {
expect(backdropClickHandler).toHaveBeenCalled();
});
it('should complete the backdrop click stream once the overlay is destroyed', () => {
let overlayRef = overlay.create(config);
overlayRef.attach(componentPortal);
viewContainerFixture.detectChanges();
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
let completeHandler = jasmine.createSpy('backdrop complete handler');
overlayRef.backdropClick().subscribe(null, null, completeHandler);
overlayRef.dispose();
expect(completeHandler).toHaveBeenCalled();
});
it('should apply the default overlay backdrop class', () => {
let overlayRef = overlay.create(config);
overlayRef.attach(componentPortal);
+2 -2
View File
@@ -57,7 +57,7 @@ export function throwMdDialogContentAlreadyAttachedError() {
],
host: {
'[class.mat-dialog-container]': 'true',
'[attr.role]': 'dialogConfig?.role',
'[attr.role]': 'config?.role',
'[@slideDialog]': '_state',
'(@slideDialog.done)': '_onAnimationDone($event)',
},
@@ -76,7 +76,7 @@ export class MdDialogContainer extends BasePortalHost {
private _document: Document;
/** The dialog configuration. */
dialogConfig: MdDialogConfig;
config: MdDialogConfig;
/** State of the dialog animation. */
_state: 'void' | 'enter' | 'exit' = 'enter';
+4 -1
View File
@@ -18,13 +18,16 @@ export class MdDialogRef<T> {
/** The instance of component opened into the dialog. */
componentInstance: T;
/** Whether the user is allowed to close the dialog. */
disableClose: boolean = this._containerInstance.config.disableClose;
/** Subject for notifying the user that the dialog has finished closing. */
private _afterClosed: Subject<any> = new Subject();
/** Result to be passed to afterClosed. */
private _result: any;
constructor(private _overlayRef: OverlayRef, public _containerInstance: MdDialogContainer) {
constructor(private _overlayRef: OverlayRef, private _containerInstance: MdDialogContainer) {
_containerInstance._onAnimationStateChange
.filter((event: AnimationEvent) => event.toState === 'exit')
.subscribe(() => this._overlayRef.dispose(), null, () => {
+22
View File
@@ -451,6 +451,28 @@ describe('MdDialog', () => {
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy();
});
it('should allow for the disableClose option to be updated while open', async(() => {
let dialogRef = dialog.open(PizzaMsg, {
disableClose: true,
viewContainerRef: testViewContainerRef
});
viewContainerFixture.detectChanges();
let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
backdrop.click();
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy();
dialogRef.disableClose = false;
backdrop.click();
viewContainerFixture.detectChanges();
viewContainerFixture.whenStable().then(() => {
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeFalsy();
});
}));
});
describe('hasBackdrop option', () => {
+10 -7
View File
@@ -16,7 +16,6 @@ import {MdDialogConfig} from './dialog-config';
import {MdDialogRef} from './dialog-ref';
import {MdDialogContainer} from './dialog-container';
import {TemplatePortal} from '../core/portal/portal';
import 'rxjs/add/operator/first';
/**
@@ -147,7 +146,7 @@ export class MdDialog {
let containerPortal = new ComponentPortal(MdDialogContainer, viewContainer);
let containerRef: ComponentRef<MdDialogContainer> = overlay.attach(containerPortal);
containerRef.instance.dialogConfig = config;
containerRef.instance.config = config;
return containerRef.instance;
}
@@ -166,14 +165,18 @@ export class MdDialog {
dialogContainer: MdDialogContainer,
overlayRef: OverlayRef,
config: MdDialogConfig): MdDialogRef<T> {
// Create a reference to the dialog we're creating in order to give the user a handle
// to modify and close it.
let dialogRef = new MdDialogRef<T>(overlayRef, dialogContainer);
if (!config.disableClose) {
// When the dialog backdrop is clicked, we want to close it.
overlayRef.backdropClick().first().subscribe(() => dialogRef.close());
// When the dialog backdrop is clicked, we want to close it.
if (config.hasBackdrop) {
overlayRef.backdropClick().subscribe(() => {
if (!dialogRef.disableClose) {
dialogRef.close();
}
});
}
// We create an injector specifically for the component we're instantiating so that it can
@@ -221,7 +224,7 @@ export class MdDialog {
*/
private _handleKeydown(event: KeyboardEvent): void {
let topDialog = this._openDialogs[this._openDialogs.length - 1];
let canClose = topDialog ? !topDialog._containerInstance.dialogConfig.disableClose : false;
let canClose = topDialog ? !topDialog.disableClose : false;
if (event.keyCode === ESCAPE && canClose) {
topDialog.close();