Reputation: 2040
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
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