Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dialog): expose close attempts #3460

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/demo-app/dialog/dialog-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ <h1>Dialog demo</h1>
Open dialog with template content
</button>

<button md-raised-button color="accent" (click)="openWithDisabledClose()">
Open dialog with disabled close and close attempts exposure
</button>

<md-card class="demo-dialog-card">
<md-card-content>
<h2>Dialog dimensions</h2>
Expand Down Expand Up @@ -67,6 +71,10 @@ <h2>Other options</h2>

<p>Last close result: {{lastCloseResult}}</p>

<ng-template>
<ng-template #templateRef>
I'm a template dialog. I've been opened {{numTemplateOpens}} times!
</ng-template>

<ng-template #disabledCloseRef>
{{ closeAttemptType ? 'Tried to close with: ' + closeAttemptType : 'Have not tried to close yet.' }}
</ng-template>
17 changes: 15 additions & 2 deletions src/demo-app/dialog/dialog-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {MdDialog, MdDialogRef, MdDialogConfig, MD_DIALOG_DATA} from '@angular/ma
export class DialogDemo {
dialogRef: MdDialogRef<JazzDialog>;
lastCloseResult: string;
closeAttemptType: string;
actionsAlignment: string;
config: MdDialogConfig = {
disableClose: false,
Expand All @@ -29,7 +30,8 @@ export class DialogDemo {
};
numTemplateOpens = 0;

@ViewChild(TemplateRef) template: TemplateRef<any>;
@ViewChild('templateRef') template: TemplateRef<any>;
@ViewChild('disabledCloseRef') templateForDisabledClose: TemplateRef<any>;

constructor(public dialog: MdDialog, @Inject(DOCUMENT) doc: any) {
// Possible useful example for the open and closeAll events.
Expand Down Expand Up @@ -63,8 +65,19 @@ export class DialogDemo {
this.numTemplateOpens++;
this.dialog.open(this.template, this.config);
}
}

openWithDisabledClose() {
let disableCloseConfig = new MdDialogConfig();
disableCloseConfig.disableClose = true;

let dialogRef = this.dialog.open(this.templateForDisabledClose, disableCloseConfig);

dialogRef.closeAttempt().subscribe((type) => {
this.closeAttemptType = type;
});

}
}

@Component({
selector: 'demo-jazz-dialog',
Expand Down
6 changes: 6 additions & 0 deletions src/lib/dialog/dialog-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ import {BasePortalHost, ComponentPortal, PortalHostDirective, TemplatePortal} fr
import {MdDialogConfig} from './dialog-config';
import {MdDialogContentAlreadyAttachedError} from './dialog-errors';
import {FocusTrapFactory, FocusTrap} from '../core/a11y/focus-trap';
import {Subject} from 'rxjs/Subject';
import 'rxjs/add/operator/first';


/** Possible states for the dialog container animation. */
export type MdDialogContainerAnimationState = 'void' | 'enter' | 'exit' | 'exit-start';

/** Possible types of close events */
export type MdDialogCloseAttempt = 'escape' | 'backdrop';

/**
* Internal component that wraps user-provided dialog content.
Expand Down Expand Up @@ -67,6 +70,9 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
/** The dialog configuration. */
dialogConfig: MdDialogConfig;

/** subject to expose any close attempt */
_closeAttempt = new Subject<MdDialogCloseAttempt>();

/** State of the dialog animation. */
_state: MdDialogContainerAnimationState = 'enter';

Expand Down
14 changes: 12 additions & 2 deletions src/lib/dialog/dialog-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import {OverlayRef, GlobalPositionStrategy} from '../core';
import {DialogPosition} from './dialog-config';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {MdDialogContainer, MdDialogContainerAnimationState} from './dialog-container';

import {
MdDialogContainer,
MdDialogContainerAnimationState,
MdDialogCloseAttempt,
} from './dialog-container';

// TODO(jelbourn): resizing
// TODO(jelbourn): afterOpen and beforeClose
Expand Down Expand Up @@ -53,6 +56,13 @@ export class MdDialogRef<T> {
return this._afterClosed.asObservable();
}

/**
* Gets an observable that is notified when a close attempt is made
*/
closeAttempt(): Observable<MdDialogCloseAttempt> {
return this._containerInstance._closeAttempt.asObservable();
}

/**
* Updates the dialog's position.
* @param position New dialog position.
Expand Down
46 changes: 46 additions & 0 deletions src/lib/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,52 @@ describe('MdDialog', () => {
});
}));

it('should let the user know that there was a close attempt via the backdrop click', async(() => {
const dialogRef = dialog.open(PizzaMsg, {
viewContainerRef: testViewContainerRef,
disableClose: true
});

let attemptType: any;

dialogRef.closeAttempt().subscribe((type) => {
attemptType = type;
});

viewContainerFixture.detectChanges();

let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;

backdrop.click();
viewContainerFixture.detectChanges();

viewContainerFixture.whenStable().then(() => {
expect(attemptType).toEqual('backdrop');
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy();
});
}));

it('should let the user know that there was a close attempt via the escape key', async(() => {
const dialogRef = dialog.open(PizzaMsg, {
viewContainerRef: testViewContainerRef,
disableClose: true
});

let attemptType: any;

dialogRef.closeAttempt().subscribe((type) => {
attemptType = type;
});

dispatchKeyboardEvent(document, 'keydown', ESCAPE);
viewContainerFixture.detectChanges();

viewContainerFixture.whenStable().then(() => {
expect(attemptType).toEqual('escape');
expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy();
});
}));

it('should notify the observers if a dialog has been opened', () => {
let ref: MdDialogRef<PizzaMsg>;
dialog.afterOpen.subscribe(r => {
Expand Down
17 changes: 15 additions & 2 deletions src/lib/dialog/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {MdDialogConfig} from './dialog-config';
import {MdDialogRef} from './dialog-ref';
import {MdDialogContainer} from './dialog-container';
import {TemplatePortal} from '../core/portal/portal';
import {Subscription} from 'rxjs/Subscription';
import 'rxjs/add/operator/first';


Expand All @@ -21,6 +22,7 @@ export class MdDialog {
private _afterAllClosedAtThisLevel = new Subject<void>();
private _afterOpenAtThisLevel = new Subject<MdDialogRef<any>>();
private _boundKeydown = this._handleKeydown.bind(this);
private _backdropClickSubscription: Subscription;

/** Keeps track of the currently-open dialogs. */
get _openDialogs(): MdDialogRef<any>[] {
Expand Down Expand Up @@ -152,6 +154,10 @@ export class MdDialog {
if (!config.disableClose) {
// When the dialog backdrop is clicked, we want to close it.
overlayRef.backdropClick().first().subscribe(() => dialogRef.close());
} else {
this._backdropClickSubscription = overlayRef.backdropClick().subscribe(() => {
dialogContainer._closeAttempt.next('backdrop');
});
}

// We create an injector specifically for the component we're instantiating so that it can
Expand Down Expand Up @@ -187,6 +193,10 @@ export class MdDialog {

// no open dialogs are left, call next on afterAllClosed Subject
if (!this._openDialogs.length) {
if (this._backdropClickSubscription) {
this._backdropClickSubscription.unsubscribe();
}

this._afterAllClosed.next();
document.removeEventListener('keydown', this._boundKeydown);
}
Expand All @@ -201,8 +211,11 @@ export class MdDialog {
let topDialog = this._openDialogs[this._openDialogs.length - 1];
let canClose = topDialog ? !topDialog._containerInstance.dialogConfig.disableClose : false;

if (event.keyCode === ESCAPE && canClose) {
topDialog.close();
if (event.keyCode === ESCAPE && topDialog) {
topDialog._containerInstance._closeAttempt.next('escape');
if (canClose) {
topDialog.close();
}
}
}
}
Expand Down