Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

#2404 Modal open calls should complete in order #2443

Closed
wants to merge 5 commits into from

Conversation

nlwillia
Copy link

Modal open calls wait on template and resolve promises. Even though the
resolution order of the promises among different modals is
non-deterministic, the open calls should complete in the same order they
were invoked.

@wesleycho
Copy link
Contributor

Is this for having multiple modals open? It should be noted that UI Bootstrap does not support multiple modals being opened at the same time.

@nlwillia
Copy link
Author

nlwillia commented Apr 5, 2015

Use case: modals bound to router state. "main.detail" is a modal detail popup. "main.detail.edit" is a nested modal on top of that. If someone follows a deep link to the edit state, then the router will issue modal.open calls in a deterministic order, but without this fix the modal resolves could complete out of order resulting in the wrong modal being on top.

There's no reason why modals shouldn't be allowed to open on top of each other. Nesting too deeply may not be great UI design, but consider a modal edit dialog with a fancy "are you sure?" exit prompt that also uses a modal. That would be two modals open at the same time. In practice, I haven't found a problem with an arbitrary level of nesting.

@chrisirhc chrisirhc added this to the Backlog milestone Apr 6, 2015
@@ -358,9 +360,26 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
var templateAndResolvePromise =
$q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
Copy link
Contributor

Choose a reason for hiding this comment

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

How about getting the top opened window's opened promise and appending it here?

You can get it by doing $modalStack.getTop().opened. You should also handle the case that there's no top window.

Copy link
Author

Choose a reason for hiding this comment

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

That's a good suggestion, but I don't think it can work because $modalStack isn't updated until templateAndResolvePromise is resolved.

Copy link
Author

Choose a reason for hiding this comment

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

I've reorganized things so that the opened promise is the only one burdened with chaining concerns. It shuffles things around a little, but it leaves the templateAndResolvePromise alone.

@chrisirhc
Copy link
Contributor

I think this is a good idea. However, I think your PR doesn't work for more modals. I've made a suggestion above that should also minimize the changes you need to make.

@nlwillia
Copy link
Author

I've committed a change that should fix the problem with more modals and updated the test to cover more scenarios.

var previous = modalOpenedPromiseChain;
modalOpenedPromiseChain = $q.all([previous || $q.when(undefined), templateAndResolvePromise])
.then(function() { return true; }, function(reason) { return reason[reason.length-1]; })
['finally'](function() { modalOpenedPromiseChain = previous; });
Copy link
Contributor

Choose a reason for hiding this comment

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

This finally may call prematurely if 3 modals are opened and the first modal's templateAndResolvePromise fails. In such a scenario, if a 4th modal is opened, the modalOpenedPromiseChain would be reset to undefined, but that's not correct.

@chrisirhc
Copy link
Contributor

This is rather complex if $modalStack isn't updated until the promise is resolved. Perhaps we need to add it to the $modalStack, or track all the waiting promises until they're resolved. The finally call can instead remove it from the list of waiting promises.

@nlwillia
Copy link
Author

@chrisirhc thank you for your comments (and your patience!). I should have realized that templateAndResolvePromise needs to remain chained because it controls insertion order onto the stack. Here's another revision that I think addresses the problems you've raised. This could still be reworked to coordinate through $modalStack if you prefer, but as is, it seems to resolve and cleanup correctly.

@wesleycho
Copy link
Contributor

Can you squash and rebase?

@@ -24,6 +24,7 @@ describe('$modal', function () {
$timeout = _$timeout_;
$q = _$q_;
$modal = _$modal_;
$modalStack = _$modalStack_;
Copy link
Contributor

Choose a reason for hiding this comment

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

Indentation is off.

@nlwillia
Copy link
Author

Not sure that rebase commit did what I wanted it to. I'll have to look at this further in another week when I'm back from vacation and have access to my dev machine.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants