Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

window.onbeforeunload - Only show warning when not submitting form [duplicate]

I am using window.onbeforeunload to prevent the user from navigating away after changing values on a form. This is working fine, except it also shows the warning when the user submits the form (not desired).

How can I do this without showing the warning when the form submits?

Current code:

var formHasChanged = false;

$(document).on('change', 'form.confirm-navigation-form input, form.confirm-navigation-form select, form.confirm-navigation-form textarea', function (e) {
    formHasChanged = true;
});

$(document).ready(function () {
    window.onbeforeunload = function (e) {
        if (formHasChanged) {
            var message = "You have not saved your changes.", e = e || window.event;
            if (e) {
                e.returnValue = message;
            }
            return message;
        }
    }
});
like image 223
mtmurdock Avatar asked Aug 01 '12 19:08

mtmurdock


People also ask

What triggers Onbeforeunload?

The onbeforeunload event occurs when the document is about to be unloaded. This event allows you to display a message in a confirmation dialog box to inform the user whether he/she wants to stay or leave the current page. The default message that appears in the confirmation box, is different in different browsers.

What is the difference between Onbeforeunload and Onunload?

Prototype: Whereas unload is a normal event that inherits from Event , beforeunload has its own prototype, BeforeUnloadEvent .

Is Beforeunload deprecated?

Deprecated. Not for use in new websites.


4 Answers

Using the form's submit event to set a flag might work for you.

 var formHasChanged = false;  var submitted = false;  $(document).on('change', 'form.confirm-navigation-form input, form.confirm-navigation-form select, form.confirm-navigation-form textarea', function (e) {     formHasChanged = true; });  $(document).ready(function () {     window.onbeforeunload = function (e) {         if (formHasChanged && !submitted) {             var message = "You have not saved your changes.", e = e || window.event;             if (e) {                 e.returnValue = message;             }             return message;         }     }  $("form").submit(function() {      submitted = true;      }); }); 
like image 71
Jay Tomten Avatar answered Sep 18 '22 17:09

Jay Tomten


you could use .on() to bind onbeforeunload and then use .off() to unbind it in form submission

$(document).ready(function () {     // Warning     $(window).on('beforeunload', function(){         return "Any changes will be lost";     });      // Form Submit     $(document).on("submit", "form", function(event){         // disable warning         $(window).off('beforeunload');     }); } 
like image 24
Brent White Avatar answered Sep 21 '22 17:09

Brent White


You can handle the submit() event, which will occur only for your form submission.

Within that event, set your flag variable formHasChanged to false to allow the unload to proceed. Also, just a suggestion, but since the purpose of that flag variable will have changed, so you may want to rename it something like 'warnBeforeUnload'

$(document).submit(function(){
    warnBeforeUnload = false;
});
like image 22
Derek Hunziker Avatar answered Sep 21 '22 17:09

Derek Hunziker


I was looking for a better solution to this. What we want is simply exclude one or more triggers from creating our "Are you sure?" dialog box. So we shouldn't create more and more workarounds for more and more side effects. What if the form is submitted without a click event of the submit button? What if our click-handler removes the isDirty status but then the form-submit is otherwise blocked afterwards? Sure we can change the behaviour of our triggers, but the right place would be the logic handling the dialog. Binding to the form's submit event instead of binding to the submit button's click event is an advantage of the answers in this thread above some others i saw before, but this IMHO just fixes the wrong approach.

After some digging in the event object of the onbeforeunload event I found the .target.activeElement property, which holds the element, which triggered the event originally. So, yay, it is the button or link or whatever we clicked (or nothing at all, if the browser itself navigated away). Our "Are you sure?" dialog logic then reduces itself to the following two components:

  1. The isDirty handling of the form:

    $('form.pleaseSave').on('change', function() {
      $(this).addClass('isDirty');
    });
    
  2. The "Are you sure?" dialog logic:

    $(window).on('beforeunload', function(event) {
      // if form is dirty and trigger doesn't have a ignorePleaseSave class
      if ($('form.pleaseSave').hasClass('isDirty')
          && !$(event.target.activeElement).hasClass('ignorePleaseSave')) {
        return "Are you sure?"
      }
      // special hint: returning nothing doesn't summon a dialog box
    });
    

It's simply as that. No workarounds needed. Just give the triggers (submit and other action buttons) an ignorePleaseSave class and the form we want to get the dialog applied to a pleaseSave class. All other reasons for unloading the page then summons our "Are you sure?" dialog.

P.S. I am using jQuery here, but I think the .target.activeElement property is also available in plain JavaScript.

like image 23
spackmat Avatar answered Sep 18 '22 17:09

spackmat