最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - prevent redirect behaviour in angularjs app - Stack Overflow

programmeradmin14浏览0评论

When a user tries to click browser back button and dere is dirty data on the form, it shows a confirmation.

Here is the angular js controller code

   function MyCtrl2($rootScope, $location, $scope) {

    $rootScope.$watch(function () {
        return $location.path();
    },

    function (newValue, oldValue) {
        if ($scope.myForm.$dirty) {
            var a = confirm('do you');
            if (!a) {
                 //how to prevent this redirect
            }
        }
    },
    true);
}

MyCtrl2.$inject = ['$rootScope', '$location', '$scope'];

But how to prevent the redirect on

When a user tries to click browser back button and dere is dirty data on the form, it shows a confirmation.

Here is the angular js controller code

   function MyCtrl2($rootScope, $location, $scope) {

    $rootScope.$watch(function () {
        return $location.path();
    },

    function (newValue, oldValue) {
        if ($scope.myForm.$dirty) {
            var a = confirm('do you');
            if (!a) {
                 //how to prevent this redirect
            }
        }
    },
    true);
}

MyCtrl2.$inject = ['$rootScope', '$location', '$scope'];

But how to prevent the redirect on

Share Improve this question edited Feb 15, 2013 at 17:59 agasthyan asked Feb 15, 2013 at 17:22 agasthyanagasthyan 7253 gold badges8 silver badges17 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 13

FYI canceling a route is now possible in Angular.

$scope.$on('$locationChangeStart', function(event, newUrl, oldUrl) {
  event.preventDefault();
});

There are two DOM events at the root of this whole problem you're trying to solve: onhashchange and onbeforeunload. onhashchange can be checked and prevented, however, the Back button on your browser will not trigger onhashchange. What's worse, onbeforeunload will not trigger if the page doesn't reload, which means if you hit Back to go to a previous hash on the page, it will not fire. Because of this, if you press Back to to go a previous route it will still leave your form.

There is also currently an oustanding issue on Angular's todo list about how they're going to allow for the cancellation of a route. I'd presume the back button to a hash issue is what's hold them up at this point.

So in the end you may want to re-engineer your solution to do something a little more drastic if you want to prevent all navigation away from your form once it's been edited. Something like storing all of the data the form is editing in $rootScope, along with a flag to show that it's dirty but incomplete, then add an event handler to routeChangeStart that checks those values and sends you back to the form.

Here's how that would work (and a plunker if you're interested):

app.config(function($routeProvider) {
  //set up the routes. (Important because we're going to navigate
  // BACK to them.)
  $routeProvider.when('/Form', {
    controller: 'FormCtrl',
    templateUrl: 'form.html'
  }).otherwise({
    controller: 'HomeCtrl',
    template: '<h3>Home</h3>' 
  });
});

app.run(function($rootScope, $location){ 
  //set up your rootScope formData object.
  $rootScope.formData = {};

  //add a routing event to check the route
  // and whether or not the data has been editted and then 
  // send it back to the proper form.
  $rootScope.$on('$routeChangeStart', function() {
    if($location.path() != '/Form' && $rootScope.formData.dirty && 
      !$rootScope.formData.complete && !confirm('Do you want to leave this form?')) {
      $location.path('/Form');
    }
  });

  //handle outright navigating away from the page.
  $(window).on('beforeunload', function() {
     if($rootScope.formData.dirty && 
      !$rootScope.formData.complete) {
         return 'Are you sure you want to navigate away from this form?';
     }
  });
});

app.controller('FormCtrl', function($scope) {
  $scope.$watch(function (){
    return $scope.myForm.$dirty;
  }, function(dirty) {
    $scope.formData.dirty = $scope.formData.dirty | dirty;
  })
});

other thoughts

Initially I had developed a directive to help with this, but I realized that it wouldn't work because of the issues I mentioned above. Regardless, for posterity's sake, here it is:

app.directive('form', function ($window){
  return {
    restrict: 'E',
    link: function(scope, elem, attrs) {

      //check for a prevent-if-dirty attribute on your form tag
      if(attrs.preventIfDirty !== undefined) {

        // first off, stop routing hash changes from 
        // changing the page.
        scope.$on('$locationChangeStart', function(event) {
          if(scope.testForm.$dirty) {
            event.preventDefault();
          }
        });

        // a little setup for our next piece
        var formName = attrs.name;
        function showWarning() {
          return 'You have changed the form';
        }

        // Now stop browser navigation from moving away
        // from your dirty form.
        scope.$watch(function (){
          return scope[formName].$dirty;
        }, function(dirty) {
          if(dirty) {
             $(window).on('beforeunload', showWarning);
          } else {
             $(window).off('beforeunload', showWarning);
          }
        });
      }
    }
  };
});

Here's a plunker demonstrating it.

发布评论

评论列表(0)

  1. 暂无评论