4

I got the snippet below from this SO post, and it works when a user tries to reload the page or close the browser etc. but if the user clicks on a link then it lets them naivagate away, and then incorrectly starts displaying the message on the wrong page. I am using pjax for the links.

   $(document).ready(function () {
       $('textarea').change(function () {
          window.onbeforeunload = function () { return "Your changes to the survey have not been saved?" };
      });
    });
Community
  • 1
  • 1
Lee
  • 8,354
  • 14
  • 55
  • 90
  • The page never really gets the status `unload` so you need to trigger that when you click a link. – putvande Aug 06 '13 at 09:30
  • Can you give a code sample please? – Lee Aug 06 '13 at 09:30
  • 3
    @lee code sample to trigger specific event? There are thousand of 'code sample' like this, try yourself to search, you should find it... – A. Wolff Aug 06 '13 at 09:34
  • Make a function that calls the `window.onbeforeunload` and bind it to your links. – putvande Aug 06 '13 at 09:36
  • @roasted you are assuming that I read putvande's answer AND have the necessary background knowledge to interpret it to 'I need to trigger a specific event', when I may have interpreted is as 'huh what?' – Lee Aug 06 '13 at 09:41
  • $('a').click(function(){ window.onbeforeunload(); }); does not work... – Lee Aug 06 '13 at 09:54
  • You probably want to be using trigger: $('a').click(function(){ $(window).trigger('beforeunload'); }); – BenWells Aug 06 '13 at 10:02
  • @BenWells that does not work either... – Lee Aug 06 '13 at 10:10

2 Answers2

8

You should use onbeforeunload like this, inconditionally:

<script type="text/javascript">
saved=true; // initially, it is saved (no action has been done)

window.onbeforeunload = confirmExit;
function confirmExit() {
    if (!saved) {
        return "You did not save, do you want to do it now?";
    }
}
</script>

It is not safe to handle this event only when another event is fired. The onchange event of your textarea here probably don't fire before you click on a link so the window won't handle the onbeforeunload at all. The link will work as expected: you will get redirected.

To deal with the saved flag, you could listen to what happens in your textarea, for example, when the user is actually typing something:

$('textarea').keyup(function(){
    saved=false;
});

Then, if you save the data in ajax, the save button could set it back to true:

$('#btnSave').click(function(){
    // ajax save
    saved=true;
});

Otherwise, it will load the next page with the saved flag on.

Frederik.L
  • 5,522
  • 2
  • 29
  • 41
3

what about something like the following? Listening on all <a> links and then, depending on whether the variable needToSave is set to true, showing the message or letting it go.

var needToSave = false; // Set this to true on some change
// listen on all <a ...> clicks
$(document).click("a", function(event){        
    if (needToSave == true) {
        alert("You need to save first");
        event.preventDefault();
        return;
    }
});

UPDATE (as per Roasted's suggestion) this should trigger the unload event every time the link is clicked and perform your existing logic:

// listen on all <a ...> clicks
$(document).click("a", function(event){        
   $(window).trigger("unload");
});

jsFiddle here - http://jsfiddle.net/k2fYM/

mara-mfa
  • 895
  • 6
  • 9
  • This looks legit, but I am still waiting to see if there is a "built in" solution before marking this as the answer. – Lee Aug 06 '13 at 10:12
  • Not sure if there is anything built in (or what you mean by that). Nevertheless, see the update what roasted meant by triggering an unload event. – mara-mfa Aug 06 '13 at 10:23
  • it does - added jsFiddle – mara-mfa Aug 06 '13 at 10:45
  • Clearly your solution does work, but just not for me for some reason :( – Lee Aug 06 '13 at 11:42
  • If you manage to put that in jsFiddle, I am sure we will find out – mara-mfa Aug 06 '13 at 11:45
  • The problem is that I am using Rails so there are a lots of little pieces that may be interfering that cannot be put on the fiddle – Lee Aug 06 '13 at 12:03
  • I used the first example but needed to add `event.stopPropagation()` *before* the return as my scenario was in an ajax environment and clicking on `a` links was also bound to other handlers. So what was happening is that the alert was firing but then the other page was loading anyway. Adding `event.stopPropagation()` stopped that. – user1063287 Feb 05 '14 at 16:12