6

If user tries to leave unsaved edited form, a message box pop-up

"This page is asking you to confirm that you want to leave - data you have entered may not be saved. Leave Page and Stay on Page"

Can we invoke this confirmation box through some special function of browser? I want to implement it in AngularJS application

enter image description here

Mike Doe
  • 16,349
  • 11
  • 65
  • 88
Anand
  • 4,523
  • 10
  • 47
  • 72
  • You must be aiming for window.confirm() method. – EricG Nov 26 '12 at 14:00
  • possibly duplicate question http://stackoverflow.com/questions/1704533/intercept-page-exit-event – SubRed Nov 26 '12 at 14:01
  • @EricG that is not a confirm prompt in the screenshot. – epascarello Nov 26 '12 at 14:09
  • @epascarello, Agreed, but actually it isnt obvious what he means. The "onbeforeunload" function cannot be invoked manually, but can be edited and this becomes clear 'whenever' it shows. The confirm dialog CAN be invoked manually but doesnt know by default whether or not the page was edited. So my answer wasnt that irrelevant compared to "onbeforeonload" I think ;) – EricG Nov 26 '12 at 15:09
  • @SubRed - this isn't actually a duplicate question, when it comes to Angular. See my answer. – Ben Lesh Nov 26 '12 at 15:15
  • @blesh Oh sorry I didn't notice this is for AngularJS application :p – SubRed Nov 26 '12 at 15:25

6 Answers6

11

Warlock's answer is partly right, but in doing so, you'd break testability.

In Angular, you'd want to use $window, and you'll want to watch $dirty on your form. You'll need to have a named form, notice name="myForm" below. Then you can $watch $dirty on the form in your $scope:

app.controller('MainCtrl', function($scope, $window) {
  $scope.name = 'World';
  var win = $window;
  $scope.$watch('myForm.$dirty', function(value) {
    if(value) {
      win.onbeforeunload = function(){
        return 'Your message here';
      };
    }
  });
});

HTML

<form name="myForm">
  Name: <input type="text" ng-model="name"/>
</form>

Here's a plunk to demonstrate: http://plnkr.co/edit/3NHpU1

Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • 3
    Thanks. But in AngularJS we have lots of partial views, each have form. This event is not being fire don view change. is there any event which get called before view-change. – Anand Nov 27 '12 at 08:39
  • Then it doesn't sound like you're using forms in angular properly. if you have `
    ` then you should be able to `$scope.$watch('whatever.$dirty)`, you'd have to do that for each form, which is a little bit of a pain, I suppose.
    – Ben Lesh Nov 27 '12 at 13:38
  • @StefanLobato Some browsers won't show prompts unless the user interacts with the page first. See notes here: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload – Ben Lesh Apr 26 '16 at 17:11
5

You could use the "onbeforeunload" event. The syntax is as follows:

window.onbeforeunload = function () {
    return "Your text string you want displayed in the box";
}

This event will popup that confirmation dialog that you described above asking whether or not the user truly wants to leave the page.

Hope this helps.

War10ck
  • 12,387
  • 7
  • 41
  • 54
5

If you want to cancel the route change when you determine your form is dirty, you can do this:

$rootScope.$on('$locationChangeStart', function(event) {
  event.preventDefault();
});

This will cancel the routing and keep you on the current page.

Joe Grund
  • 4,449
  • 2
  • 17
  • 9
4

I liked @blesh's answer, but I think it fails to account for internal url changes (for example, if you use ngView on your application and visit different internal views). window.onbeforeunload never gets called when the hash # changes. In this case, you have to listen to both window.onbeforeunload and $locationChangeStart:

app.controller('OtherCtrl', ['$scope', '$window', '$location', '$rootScope', function($scope, $window, $location, $rootScope) {
  $scope.message = "This time you get a confirmation.";
  $scope.navigate = function() {
    $location.path("/main");
  }
  var getMessage = function() {
    if($scope.myForm.$dirty) {
      return $scope.message;
    } else {
      return null;
    }
  }
  $window.onbeforeunload = getMessage;
  var $offFunction = $rootScope.$on('$locationChangeStart', function(e) {
    var message = getMessage();
    if(message && !confirm($scope.message)) {
      e.preventDefault();
    } else {
      $offFunction();
    }
  });
}]);

See plunkr here: http://plnkr.co/edit/R0Riek?p=preview

yourdeveloperfriend
  • 1,600
  • 1
  • 9
  • 19
  • I'd have to agree with your assessment. Just listening for onbeforeunload doesn't handle angular route changes, which is a really important component of solving this problem. – developering Mar 18 '15 at 22:56
1

You can easily protect your form with jQuery with this simple unobtrusive code. Put in just before your </body> closing tag.

(function () {
    jQuery('form').one('change', function () {
        window.onbeforeunload = function () {
            return 'Form protection';
        };
    });
})();
Mike Doe
  • 16,349
  • 11
  • 65
  • 88
0

I think you would need to use $window.alert or $window.confirm or beforeroutechange

Angular documentation

ch4nd4n
  • 4,110
  • 2
  • 21
  • 43