quma
quma

Reputation: 5719

AngularJS ui-route exit page

I need a possibility to ask the user if he/she is leaving a page. I read that his would be a possibility but the event is fired when I enter the page and not when I leave the page. onExit would work but this event I have to defined at the ... .routes.js and I need access to properties and functions at the controller. Is there an event that is fired by exit of page?

$scope.$on('$locationChangeStart', function( event ) {
        var answer = confirm("Are you sure you want to leave this page?")
        if (!answer) {
            event.preventDefault();
        }
    });

Upvotes: 13

Views: 4559

Answers (3)

Muhammad Abid
Muhammad Abid

Reputation: 801

This could be achieved in multiple ways,

1- Use $locationChangeStart technique and verify if this is current location before displaying message. example below,

 $scope.$on('$locationChangeStart', function( event, next, current) {
    // match Current URL and If it true show message.
    if (current.match("\/yourCurrentRoute")) {
          var answer = confirm("Are you sure you want to leave this page?");
          if (!answer) {
               event.preventDefault();
          }else {
              //Do whatever else you want to do 
          }
    }  
});

2- In case you are using Ui-Router it has onExit call back option, example below,

    $stateProvider.state("contacts", { 
           template: "<h1>{{title}}</h1>",
           resolve: { title: 'My Contacts' },
           controller: function($scope, title){
                  $scope.title = title;
           },
          onExit: function(title){
              if(title){ ... do something ... }
          }
   })

3 - there is a non-angular way to do it as well.

window.onbeforeunload = function (event) {
  var message = 'Sure you want to leave?';
  if (typeof event == 'undefined') {
    event = window.event;
  }
  if (event) {
    event.returnValue = message;
  }
  return message;
}

4 - Use this directive if this page has form, It automatically cleans itself up when the form is unloaded. If you want to prevent the prompt from firing (e.g. because you successfully saved the form), call $scope.FORMNAME.$setPristine(), where FORMNAME is the name of the form you want to prevent from prompting.

.directive('dirtyTracking', [function () {
    return {
        restrict: 'A',
        link: function ($scope, $element, $attrs) {
            function isDirty() {
                var formObj = $scope[$element.attr('name')];
                return formObj && formObj.$pristine === false;
            }

            function areYouSurePrompt() {
                if (isDirty()) {
                    return 'You have unsaved changes. Are you sure you want to leave this page?';
                }
            }

            window.addEventListener('beforeunload', areYouSurePrompt);

            $element.bind("$destroy", function () {
                window.removeEventListener('beforeunload', areYouSurePrompt);
            });

            $scope.$on('$locationChangeStart', function (event) {
                var prompt = areYouSurePrompt();
                if (!event.defaultPrevented && prompt && !confirm(prompt)) {
                    event.preventDefault();
                }
            });
        }
    };
}]);

5- there is another way to use $destroy, it is fired when controller is destroyed , write it inside controller.

 $scope.$on('$destroy', function () {
     // display error message 
 });

Upvotes: 5

beaver
beaver

Reputation: 17647

The $stateChangeStart you mentioned is good for your needs: in fact from ui-router documentation:

$stateChangeStart - fired when the transition begins.

that is when user is leaving the previous state.

Here you can find an answer to a very similar question:

Can I stop the transition to the next state in an onExit?

and ther is also a working snippet.

Upvotes: 8

Abhilash Augustine
Abhilash Augustine

Reputation: 4208

You can either use $stateChangeStart or $stateChangeSuccess events in the ui-route.

// fire when the state is started to change
$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams, options){ 
    // event.preventDefault(); // block transition from happening
});

// fire when the transition completed (onExit)
$rootScope.$on('$stateChangeSuccess', 
function(event, toState, toParams, fromState, fromParams){ 
    // do something 
    if(someCondition){
        $state.go(fromState); // get back to the state
    }
})

Upvotes: 2

Related Questions