diff --git a/src/modal/docs/readme.md b/src/modal/docs/readme.md index 1a0be3f066..27904f5699 100644 --- a/src/modal/docs/readme.md +++ b/src/modal/docs/readme.md @@ -35,6 +35,8 @@ In addition the scope associated with modal's content is augmented with 2 method Those methods make it easy to close a modal window without a need to create a dedicated controller. +If the $scope is destroyed via unexpected mechanism, such as it being passed in the modal options and a $route/$state transition occurs, the modal will be dismissed with the value `$uibModal`. + Finally, a `modal.closing` event is broadcast to the modal scope before the modal closes. If the listener calls preventDefault on the event, then the modal will remain open. The $close and $dismiss methods return true if the event was allowed. The event itself includes a parameter for the result/reason and a boolean parameter that indicates diff --git a/src/modal/modal.js b/src/modal/modal.js index 784688b92a..89ab44134c 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -375,6 +375,7 @@ angular.module('ui.bootstrap.modal', []) $modalStack.close = function (modalInstance, result) { var modalWindow = openedWindows.get(modalInstance); if (modalWindow && broadcastClosing(modalWindow, result, true)) { + modalWindow.value.modalScope.$$uibDestructionScheduled = true; modalWindow.value.deferred.resolve(result); removeModalWindow(modalInstance, modalWindow.value.modalOpener); return true; @@ -385,6 +386,7 @@ angular.module('ui.bootstrap.modal', []) $modalStack.dismiss = function (modalInstance, reason) { var modalWindow = openedWindows.get(modalInstance); if (modalWindow && broadcastClosing(modalWindow, reason, false)) { + modalWindow.value.modalScope.$$uibDestructionScheduled = true; modalWindow.value.deferred.reject(reason); removeModalWindow(modalInstance, modalWindow.value.modalOpener); return true; @@ -524,6 +526,12 @@ angular.module('ui.bootstrap.modal', []) modalScope.$close = modalInstance.close; modalScope.$dismiss = modalInstance.dismiss; + modalScope.$on('$destroy', function() { + if (!modalScope.$$uibDestructionScheduled) { + modalScope.$dismiss('$uibModal'); + } + }); + var ctrlInstance, ctrlLocals = {}; var resolveIter = 1; diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index f70ae6ee00..c95e3c925d 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -314,6 +314,17 @@ describe('$modal', function () { expect(modal.result).toBeRejectedWith('esc'); }); + it('should reject returned promise on unexpected closure', function () { + var scope = $rootScope.$new(); + var modal = open({template: '
Content
', scope: scope}); + scope.$destroy(); + + expect(modal.result).toBeRejectedWith('$uibModal'); + + $animate.triggerCallbacks(); + expect($document).toHaveModalsOpen(0); + }); + it('should expose a promise linked to the templateUrl / resolve promises', function () { var modal = open({template: '
Content
', resolve: { ok: function() {return $q.when('ok');}