4

I have a form in a controller. If there are unsaved change I want to warn the user about loosing them when leaving.

First I tried:

$scope.$on('$locationChangeStart', function (event, next, current) {

    if ($scope.settingsForm.$dirty) {

        event.preventDefault();

        $scope.theUserWantsToLeave(function (result) {

            if (result === "LEAVE") {

                $location.path($location.url(next).hash());
                $scope.$apply();

            }
        });
    }

The code above throws an error in the line $scope.$apply();:

Error: $digest already in progress

removing this line just don't execute the redirect.

What would be the right way to do it?

===

Edit:

Other option I tried is handling it by reacting only when I need to cancel the redirection:

  $scope.$on('$locationChangeStart', function (event, next, current) {

    if ($scope.settingsForm.$dirty) {

      $scope.theUserWantsToLeave(function (result) {

        if (result === "STAY_HERE") {

          event.preventDefault();

        }
          });
        }
});

when doing things this way, the UI is breaking (I see the dialog and then it gone). Seems like I can't call another async method while handling event.

Roy Tsabari
  • 2,000
  • 6
  • 26
  • 41
  • Can you just leave the data set in the form controller and let the user return whenever they want? If you were preserving it you could also do the dialog and just schedule a return for after the change succeeds rather than trying to break the locationchange. – lossleader Jul 11 '13 at 09:05
  • 2
    Seen this? http://stackoverflow.com/questions/16344223/angularjs-cancel-route-change-event?rq=1 – aet Sep 24 '13 at 17:45

1 Answers1

1

I've managed to interrupt by the route change by listening for $locationChangeSuccess and then assigning $route.current to the last route.

Also, if $scope.theUserWantsToLeave is async, then the callback passed to it may fire too late to stop the route change. You could get around an async call by using a blocking flag, such as okToDiscardChanges in my examples.

JS:

$scope.okToDiscardChanges = false;

var lastRoute = $route.current;    
$scope.$on('$locationChangeSuccess', function () {
    if ($scope.settingsForm.$dirty && !$scope.okToDiscardChanges) {
        $route.current = lastRoute;
        $scope.errorMessage = 'You have unsaved changes. Are you sure you want to leave?';
    }
});

HTML:

<form name="settingsForm">
    <!-- form stuff -->
</form>

<div ng-show="errorMessage">
    {{ errorMessage }}
    <label>
        <input type="checkbox" ng-model="okToDiscardChanges"> Discard Changes
    </label>
</div>

Hope this works!

wmluke
  • 309
  • 1
  • 6