What is the best way to track changes in a form via javascript?

Solution 1:

Loop through all the input elements, and put an onchange handler on each. When that fires, set a flag which lets you know the form has changed. A basic version of that would be very easy to set up, but wouldn't be smart enough to recognize if someone changed an input from "a" to "b" and then back to "a". If it were important to catch that case, then it'd still be possible, but would take a bit more work.

Here's a basic example in jQuery:

$("#myForm")
    .on("input", function() {
        // do whatever you need to do when something's changed.
        // perhaps set up an onExit function on the window
        $('#saveButton').show();
    })
;

Solution 2:

Text form elements in JS expose a .value property and a .defaultValue property, so you can easily implement something like:

function formChanged(form) {
  for (var i = 0; i < form.elements.length; i++) {
      if(form.elements[i].value != form.elements[i].defaultValue) return(true);
  }
  return(false);
}

For checkboxes and radio buttons see whether element.checked != element.defaultChecked, and for HTML <select /> elements you'll need to loop over the select.options array and check for each option whether selected == defaultSelected.

You might want to look at using a framework like jQuery to attach handlers to the onchange event of each individual form element. These handlers can call your formChanged() code and modify the enabled property of your "save" button, and/or attach/detach an event handler for the document body's beforeunload event.

Solution 3:

Here's a javascript & jquery method for detecting form changes that is simple. It disables the submit button until changes are made. It detects attempts to leave the page by means other than submitting the form. It accounts for "undos" by the user, it is encapsulated within a function for ease of application, and it doesn't misfire on submit. Just call the function and pass the ID of your form.

This function serializes the form once when the page is loaded, and again before the user leaves the page. If the two form states are different, the prompt is shown.

Try it out: http://jsfiddle.net/skibulk/ev5rE/

function formUnloadPrompt(formSelector) {
    var formA = $(formSelector).serialize(), formB, formSubmit = false;

    // Detect Form Submit
    $(formSelector).submit( function(){
        formSubmit = true;
    });

    // Handle Form Unload    
    window.onbeforeunload = function(){
        if (formSubmit) return;
        formB = $(formSelector).serialize();
        if (formA != formB) return "Your changes have not been saved.";
    };

    // Enable & Disable Submit Button
    var formToggleSubmit = function(){
        formB = $(formSelector).serialize();
        $(formSelector+' [type="submit"]').attr( "disabled", formA == formB);
    };

    formToggleSubmit();
    $(formSelector).change(formToggleSubmit);
    $(formSelector).keyup(formToggleSubmit);
}



// Call function on DOM Ready:

$(function(){
    formUnloadPrompt('form');
});