diff --git a/src/modal/docs/readme.md b/src/modal/docs/readme.md index c77d1ebb47..14fe83afdf 100644 --- a/src/modal/docs/readme.md +++ b/src/modal/docs/readme.md @@ -29,6 +29,7 @@ The `open` method returns a modal instance, an object with the following propert * `dismiss(reason)` - a method that can be used to dismiss a modal, passing a reason * `result` - a promise that is resolved when a modal is closed and rejected when a modal is dismissed * `opened` - a promise that is resolved when a modal gets opened after downloading content's template and resolving all variables +* `closed` - a promise that is resolved when a modal is closed and the animation completes * `rendered` - a promise that is resolved when a modal is rendered. In addition the scope associated with modal's content is augmented with 2 methods: diff --git a/src/modal/modal.js b/src/modal/modal.js index cbed4c7243..ae0e66e5b5 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -306,7 +306,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) } } - function removeAfterAnimate(domEl, scope, done) { + function removeAfterAnimate(domEl, scope, done, closedDeferred) { var asyncDeferred; var asyncPromise = null; var setIsAsync = function() { @@ -336,6 +336,9 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) event: 'leave' }).start().then(function() { domEl.remove(); + if (closedDeferred) { + closedDeferred.resolve(); + } }); scope.$destroy(); @@ -392,6 +395,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) openedWindows.add(modalInstance, { deferred: modal.deferred, renderDeferred: modal.renderDeferred, + closedDeferred: modal.closedDeferred, modalScope: modal.scope, backdrop: modal.backdrop, keyboard: modal.keyboard, @@ -579,12 +583,14 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) $modal.open = function(modalOptions) { var modalResultDeferred = $q.defer(); var modalOpenedDeferred = $q.defer(); + var modalClosedDeferred = $q.defer(); var modalRenderDeferred = $q.defer(); //prepare an instance of a modal to be injected into controllers and returned to a caller var modalInstance = { result: modalResultDeferred.promise, opened: modalOpenedDeferred.promise, + closed: modalClosedDeferred.promise, rendered: modalRenderDeferred.promise, close: function (result) { return $modalStack.close(modalInstance, result); @@ -655,6 +661,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap']) scope: modalScope, deferred: modalResultDeferred, renderDeferred: modalRenderDeferred, + closedDeferred: modalClosedDeferred, content: tplAndVars[0], animation: modalOptions.animation, backdrop: modalOptions.backdrop, diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index d6f1ac935f..413741fcf0 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -388,6 +388,20 @@ describe('$uibModal', function () { expect($document).toHaveModalsOpen(0); }); + it('should resolve the closed promise when modal is closed', function() { + var modal = open({template: '
Content
'}); + close(modal, 'closed ok'); + + expect(modal.closed).toBeResolvedWith(undefined); + }); + + it('should resolve the closed promise when modal is dismissed', function() { + var modal = open({template: '
Content
'}); + dismiss(modal, 'esc'); + + expect(modal.closed).toBeResolvedWith(undefined); + }); + it('should expose a promise linked to the templateUrl / resolve promises', function() { var modal = open({template: '
Content
', resolve: { ok: function() {return $q.when('ok');}