Roy Tsabari
Roy Tsabari

Reputation: 2040

AngularJS- Prompting the user before routing to other controller to save changes

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.

Upvotes: 4

Views: 1870

Answers (1)

wmluke
wmluke

Reputation: 309

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!

Upvotes: 1

Related Questions