Need to close modal exit from state

I am using UI-Router and angular bootstrap-ui. I have a state setting for creating a modal "onEnter". I'm having problems right now when I try to close the modal "onExit". Here is the main condition. It will open modal mode when "item.detail" is entered, and it will go to "elements" when this modal is closed or rejected.

.state('items.detail', { url: '/{id}', onEnter: function ($stateParams, $state, $modal, $resource) { var modalInstance = $modal.open({ templateUrl: 'views/modal/item-detail.html', controller: 'itemDetailCtrl' }) .result.then(function () { $state.transitionTo('items'); }, function () { $state.transitionTo('items'); }); } }) 

I tried using the onExit handler. But they could not access the modalInstance or the area in which the modal is located inside this handler. Everything that I try to enter appears undefined.

 .state('items.detail', { url: '/{id}', onEnter: function ($stateParams, $state, $modal, $resource) { var modalInstance = $modal.open({ templateUrl: 'views/modal/item-detail.html', controller: 'itemDetailCtrl' }) .result.then(function () { $state.transitionTo('items'); }, function () { $state.transitionTo('items'); }); }, onExit: function ($scope) { controller: function ($scope, $modalInstance, $modal) { $modalInstance.dismiss(); }; } }) 

from my modal controller, I tried listening for state changes.

 $scope.$on('$stateChangeStart', function() { $modalInstance.dismiss(); }); 

I tried this as with $ scope. $ on and $ rootScope. $ on and both of these work, but in the end they are called every time I switch between any states. This happens only after I opened the modal.

In case this last bit is unclear ... When I update my angular application, I can switch between all my other states without calling this listener event, but after I open this modal, all my state changes will be called by this listener , even after the modal is closed.

+6
source share
3 answers

I think you can better organize your modal behavior. I would not use the onEnter and onExit handlers inside the state definition. Instead, it is better to define the controller that the modal should handle:

 .state('items.detail', { url: '/{id}', controller:'ItemDetailsController', template: '<div ui-view></div>' }) 

Then define your controller:

 .controller('ItemDetailsController', [ function($stateParams, $state, $modal, $resource){ var modalInstance = $modal.open({ templateUrl: 'views/modal/item-detail.html', controller: 'ModalInstanceCtrl', size: size, resolve: { itemId: function () { return $stateParams.id; } modalInstance.result.then(function () { $state.go('items'); }, function () { $state.go('items'); }); } }); } ]) 

Then define your ModalInstanceCtrl:

 .controller('ModalInstanceCtrl', [ function ($scope, $modalInstance, itemId) { //Find your item from somewhere using itemId and some services //and do your stuff $scope.ok = function () { $modalInstance.close('ok'); }; $scope.cancel = function () { $modalInstance.dismiss('cancel'); }; }; ]); 

Thus, the modal will be closed in ModalInstanceCtrl, and you will not worry about the state of the onExit handler.

About the listener added to the $ scope. It seems that when you add a listener and never delete it every time your state changes, it causes a memory leak, and the handler function runs every time your application changes its state! So itโ€™s better to get rid of this event listener, since you really don't need it.

+3
source

Although the question is quite old, since recently I came across the same situation and came up with a better solution, I decided to share my results here. The key point is moving the $ modal.open service to the permission part, which is a type of preload data and $ promise services, and then introduces the allowed Instance model to onEnter, onExit, etc. Codes may look like this

 .state('items.detail', { url: '/{id}', resolve: { modalInstance: function(){ return $modal.open({ templateUrl: 'views/modal/item-detail.html', controller: 'itemDetailCtrl' }) }, }, onEnter: function ($stateParams, $state, modalInstance, $resource) { modalInstance .result.then(function () { $state.transitionTo('items'); }, function () { $state.transitionTo('items'); }); }, onExit: function (modalInstance) { if (modalInstance) { modalInstance.close(); } } }) 
+5
source

You can prevent state exiting by listening to the $stateChangeStart event

 $scope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){ console.log('$stateChangeStart', toState); if (toState.name != 'items.list'){ event.preventDefault(); var top = $modalStack.getTop(); if (top) { $modalStack.dismiss(top.key); } $state.go('items.list'); } }); 
+2
source

All Articles