Skip to content

Commit

Permalink
fix(dialog): prevent dialog from opening while another dialog is anim…
Browse files Browse the repository at this point in the history
…ating (#5769)

Prevents dialogs from being opened while other dialogs are animating.

Fixes #5713.
  • Loading branch information
crisbeto authored and andrewseguin committed Jul 25, 2017
1 parent b105039 commit 36f708c
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/lib/dialog/dialog-container.ts
Expand Up @@ -68,6 +68,7 @@ export function throwMdDialogContentAlreadyAttachedError() {
'[attr.aria-labelledby]': '_ariaLabelledBy',
'[attr.aria-describedby]': '_config?.ariaDescribedBy || null',
'[@slideDialog]': '_state',
'(@slideDialog.start)': 'this._isAnimating = true',
'(@slideDialog.done)': '_onAnimationDone($event)',
},
})
Expand Down Expand Up @@ -96,6 +97,9 @@ export class MdDialogContainer extends BasePortalHost {
/** ID of the element that should be considered as the dialog's label. */
_ariaLabelledBy: string | null = null;

/** Whether the container is currently mid-animation. */
_isAnimating = false;

constructor(
private _ngZone: NgZone,
private _elementRef: ElementRef,
Expand Down Expand Up @@ -175,5 +179,7 @@ export class MdDialogContainer extends BasePortalHost {
this._restoreFocus();
this._onAnimationStateChange.complete();
}

this._isAnimating = false;
}
}
5 changes: 5 additions & 0 deletions src/lib/dialog/dialog-ref.ts
Expand Up @@ -97,6 +97,11 @@ export class MdDialogRef<T> {
return this;
}

/** Returns whether the dialog is animating. */
_isAnimating(): boolean {
return this._containerInstance._isAnimating;
}

/** Fetches the position strategy object from the overlay ref. */
private _getPositionStrategy(): GlobalPositionStrategy {
return this._overlayRef.getState().positionStrategy as GlobalPositionStrategy;
Expand Down
14 changes: 11 additions & 3 deletions src/lib/dialog/dialog.ts
Expand Up @@ -115,11 +115,19 @@ export class MdDialog {
*/
open<T>(componentOrTemplateRef: ComponentType<T> | TemplateRef<T>,
config?: MdDialogConfig): MdDialogRef<T> {

const inProgressDialog = this._openDialogs.find(dialog => dialog._isAnimating());

// If there's a dialog that is in the process of being opened, return it instead.
if (inProgressDialog) {
return inProgressDialog;
}

config = _applyConfigDefaults(config);

let overlayRef = this._createOverlay(config);
let dialogContainer = this._attachDialogContainer(overlayRef, config);
let dialogRef =
const overlayRef = this._createOverlay(config);
const dialogContainer = this._attachDialogContainer(overlayRef, config);
const dialogRef =
this._attachDialogContent(componentOrTemplateRef, dialogContainer, overlayRef, config);

if (!this._openDialogs.length) {
Expand Down

2 comments on commit 36f708c

@tom-b-wright
Copy link

@tom-b-wright tom-b-wright commented on 36f708c Sep 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello,

dialog.ts lines 119-124
This code change makes me to execute the following method before each MdDialog.open(...) to allow opening 'sub' dialogs:
((): void => this.dialog.openDialogs.forEach(x =>
(x)._containerInstance._isAnimating = false));

I am using Safari on MacOS.
For some reason the _isAnimating flag never becomes false. Maybe this is a bug.

Real world case: On a dialog there is a list of items. The items are each having a delete button that pop-ups a "Please confirm deleting..." dialog. Depending on the dialog result the delete operation is performed. With this change the delete operation is subscribing to the original dialog result and when I close the dialog containing the item list: the delete operation is executed (the user is never prompted to have a chance to cancel the operation). Probably my explanation isn't clear, but what matters is: returning a dialog reference belonging to another dialog is unfortunate. I recommend throwing an exception instead of returning the first '_isAnimating' dialog's reference.

@malikoski
Copy link

@malikoski malikoski commented on 36f708c Oct 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, if I have one dialog, and I want a another confirmation or other operation information, I can't open this new subdialog. Or then, the flag _isAnimating never change to false.

Please sign in to comment.