Alert for unsaved changes in form

JavascriptJquery

Javascript Problem Overview


I want to write Jquery code in master file, so that if there if user changes page and there is any unsaved changes user should get alert. I got one answer from this: link

However in most solution I will have to write code on all pages. I want it to write only at one place so that everybody dont have to worry to write it in their modules. My code is like:

<script type="text/javascript">
    var isChange;
    $(document).ready(function () {
        $("input[type='text']").change(function () {
            isChange = true;
        })
    });
    $(window).unload(function () {
        if (isChange) {
            alert('Handler for .unload() called.');
        }
    });

</script>

But everytime i make changes in text boxes .change() event is not firing.

What can be wrong in the code?

EDIT: I changed .change() to .click and it is fired. i am using jquery 1.4.1..is it because of jquery version that change() is not working?

Javascript Solutions


Solution 1 - Javascript

This is what i am using, Put all this code in a separate JS file and load it in your header file so you will not need to copy this again and again:

var unsaved = false;

$(":input").change(function(){ //triggers change in all input fields including text type
	unsaved = true;
});
		
function unloadPage(){ 
	if(unsaved){
		return "You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?";
	}
}
		
window.onbeforeunload = unloadPage;

EDIT for $ not found:

This error can only be caused by one of three things:

> 1. Your JavaScript file is not being properly loaded into your page > 2. You have a botched version of jQuery. This could happen because someone edited the core file, or a plugin may have overwritten the $ > variable. > 3. You have JavaScript running before the page is fully loaded, and as such, before jQuery is fully loaded.

Make sure all JS code is being placed in this:

$(document).ready(function () {
  //place above code here
});

Edit for a Save/Send/Submit Button Exception

$('#save').click(function() {
    unsaved = false;
});

Edit to work with dynamic inputs

// Another way to bind the event
$(window).bind('beforeunload', function() {
    if(unsaved){
        return "You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?";
    }
});

// Monitor dynamic inputs
$(document).on('change', ':input', function(){ //triggers change in all input fields including text type
    unsaved = true;
});

Add the above code in your alert_unsaved_changes.js file.

Hope this helps.

Solution 2 - Javascript

A version that use serialization of the form :

Execute this code, when dom ready :

// Store form state at page load
var initial_form_state = $('#myform').serialize();

// Store form state after form submit
$('#myform').submit(function(){
  initial_form_state = $('#myform').serialize();
});

// Check form changes before leaving the page and warn user if needed
$(window).bind('beforeunload', function(e) {
  var form_state = $('#myform').serialize();
  if(initial_form_state != form_state){
    var message = "You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?";
    e.returnValue = message; // Cross-browser compatibility (src: MDN)
    return message;
  }
});

If the user change a field then manually rollback, no warn is displayed

Solution 3 - Javascript

change event is fired once the user blurs from input not on every single character inputed.

If you need it to be called every time something is changed (even if focus is still in that input field) you would have to rely on combination of keyup and bunch of events to keep track of pasting/cuting using mouse only.

P.S. I hope you're aware that your approach to detecting changes isn't the best one? If user input some text, leaves the field and then reverts the changes the script would still alert him about modified text.

Solution 4 - Javascript

you should register events for not only inputs but also textareas, if you mean textarea with text box. You can use keyup for isChange, so that you don't wait for user to blur from this area.

$("input[type='text'], textarea").keyup(function () {
    isChange = true;
})

Solution 5 - Javascript

Why not simply bind the event to the change callback?

$(":input").change(function()
{
    $(window).unbind('unload').bind('unload',function()
    {
        alert('unsaved changes on the page');
    });
});

As an added bonus, you can use confirm and select the last element that triggered the change event:

$(":input").change(function()
{
    $(window).unbind('unload').bind('unload',(function(elem)
    {//elem holds reference to changed element
        return function(e)
        {//get the event object:
            e = e || window.event;
            if (confirm('unsaved changes on the page\nDo you wish to save them first?'))
            {
                elem.focus();//select element
                return false;//in jQuery this stops the event from completeing
            }
        }
    }($(this)));//passed elem here, I passed it as a jQ object, so elem.focus() works
    //pass it as <this>, then you'll have to do $(elem).focus(); or write pure JS
});

If you have some save button, make sure that that unbinds the unload event, though:

$('#save').click(function()
{
    $(window).unbind('unload');
    //rest of your code here
});

Solution 6 - Javascript

This is really just a different version of @AlphaMale's answer but improved in a few ways:

# Message displayed to user. Depending on browser and if it is a turbolink,
# regular link or user-driven navigation this may or may not display.
msg = "This page is asking you to confirm that you want to leave - data you have entered may not be saved."

# Default state
unsaved = false

# Mark the page as having unsaved content
$(document).on 'change', 'form[method=post]:not([data-remote]) :input', -> unsaved = true

# A new page was loaded via Turbolinks, reset state
$(document).on 'page:change', -> setTimeout (-> unsaved = false), 10

# The user submitted the form (to save) so no need to ask them.
$(document).on 'submit', 'form[method=post]', ->
  unsaved = false
  return

# Confirm with user if they try to go elsewhere
$(window).bind 'beforeunload', -> return msg if unsaved

# If page about to change via Turbolinks also confirm with user
$(document).on 'page:before-change', (event) ->
  event.preventDefault() if unsaved && !confirm msg

This is better in the following ways:

  • It is coffeescript which IMHO automatically makes it better. :)
  • It is entirely based on event bubbling so dynamic content is automatically handled (@AlphaMale's update also has this).
  • It only operates on POST forms as GET forms do not have data we typically want to avoid loosing (i.e. GET forms tend to be search boxes and filtering criteria).
  • It doesn't need to be bound to a specific button for carrying out the save. Anytime the form is submitted we assume that submission is saving.
  • It is Turbolinks compatible. If you don't need that just drop the two page: event bindings.
  • It is designed so that you can just include it with the rest of your JS and your entire site will be protected.

Solution 7 - Javascript

I use $('form').change etc. function to set a dirty bit variable. Not suitable to catch all changes (as per previous answers), but catches all that I'm interested in, in my app.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1181942View Question on Stackoverflow
Solution 1 - JavascriptAlphaMaleView Answer on Stackoverflow
Solution 2 - Javascriptfabien-michelView Answer on Stackoverflow
Solution 3 - JavascriptWTKView Answer on Stackoverflow
Solution 4 - JavascriptsedranView Answer on Stackoverflow
Solution 5 - JavascriptElias Van OotegemView Answer on Stackoverflow
Solution 6 - JavascriptEric AndersonView Answer on Stackoverflow
Solution 7 - JavascriptChalkyView Answer on Stackoverflow