Is there a way to automatically close Angular UI Bootstrap modal when route changes?

30,405

Solution 1

If you want all the opened modals to be closed whenever a route is changed successfully, you could do it in one central place by listening to the $routeChangeSuccess event, for example in a run block of your app:

var myApp = angular.module('app', []).run(function($rootScope, $uibModalStack) {
  $uibModalStack.dismissAll();
}); 

Here you can see that the $uibModalStack service gets injected on which you can call the dismissAll method - this call will close all the currently opened modals.

So, yes, you can handle modals closing centrally, in one place, with one line of code :-)

Solution 2

A better way is to see that whenever a Popup (Modal) is open, on Browser Back button click (or Keyboard Back), we stop the URL change and just close the Popup. This works for a better User Experience in my Project.

The Browser Back button works normally if there is no Modal opened.

use:

$uibModalStack.dismiss(openedModal.key);

or

$uibModalStack.dismissAll;

Sample code:

.run(['$rootScope', '$uibModalStack',
    function ($rootScope,  $uibModalStack) {       
        // close the opened modal on location change.
        $rootScope.$on('$locationChangeStart', function ($event) {
            var openedModal = $uibModalStack.getTop();
            if (openedModal) {
                if (!!$event.preventDefault) {
                    $event.preventDefault();
                }
                if (!!$event.stopPropagation) {
                    $event.stopPropagation();
                }
                $uibModalStack.dismiss(openedModal.key);
            }
        });
    }]);

Solution 3

I don't actually use Angular UI Bootstrap, but from looking at the docs, it looks like there is a close() method on the $modalInstance object.

So taking the example from the docs, this should work:

var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
    $scope.items = items;
    $scope.selected = {
        item: $scope.items[0]
    };
    $scope.ok = function () {
        $modalInstance.close($scope.selected.item);
    };
    $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
    };

    // this will listen for route changes and call the callback
    $scope.$on('$routeChangeStart', function(){
        $modalInstance.close();
    });
};

Hope that helps.

Solution 4

I resolved this issue by doing something like this:

$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){
$modalStack.dismissAll();
});

Solution 5

I am keeping this logic in the modal controller. You can listen to $locationChangeStart event and close modal there. It is also good to remove listener after, especially if you have registered a listener on $rootScope:

angular.module('MainApp').controller('ModalCtrl',['$scope','$uibModalInstance',
function ($scope, $uibModalInstance) {

  var dismissModalListener = $scope.$on('$locationChangeStart', function () {
    $uibModalInstance.close();
  });

  $scope.$on('$destroy', function() {
    dismissModalListener();
  });

}]);
Share:
30,405
szimek
Author by

szimek

Updated on July 09, 2022

Comments

  • szimek
    szimek almost 2 years

    I've got links in templates inside modals. When I click them, the current page changes, but the overlay and modal stay. I could add ng-click="dimiss()" to every link in all templates in modals, but is there a better way? E.g. to close it automatically on successful route change or add just one ng-click per template to handle all links?

  • szimek
    szimek almost 10 years
    It works almost fine :) I've got "sign in" modal with a link to "terms of service" page. The button to open this modal is in the header bar that is always visible, so it's possible to open this modal on "terms of service" page as well. When I click this link while I'm on "terms of service" page, the route doesn't change and success event is not fired. Any idea how to solve it? Is there any event fired in such case that I could listen to?
  • boatcoder
    boatcoder almost 10 years
    Change the url when you click that button?
  • szimek
    szimek almost 10 years
    @Mark0978 The issue is that you're on the same page to which the link inside the modal points to, so there's no URL change.
  • boatcoder
    boatcoder almost 10 years
    I'm saying change that behavior. Make the TOS page a new URL, voila!
  • Per Quested Aronsson
    Per Quested Aronsson over 9 years
    app.run(function ($rootScope, $modalStack) { $rootScope.$on('$routeChangeSuccess', function (newVal, oldVal) { if (oldVal !== newVal) { $modalStack.dismissAll(); } }); });
  • chovy
    chovy almost 8 years
    Unknown provider: $uibModalStackProvider
  • Kiran Kumar
    Kiran Kumar over 7 years
    Do you know the solution for this in angular 2.
  • Leon Gaban
    Leon Gaban over 7 years
    Do you have a link to the uibModalStack documentation? Can't find it anywhere...
  • bits
    bits almost 5 years
    I used this code, but this conflicts with uirouter. When I have a model with a button which initialises a state change, the modal is closed, the state is changed, BUT the URL isn't changed to the state's URL. This is because of the code above. I'm still looking for a solution. If I have it, I will post it here.