You may be familiar with using javascript events such as ‘onblur’ or ‘keyup’ to fire handler methods or even ajax methods to update UI elements. One of the challenges I faced recently was detecting changes in a web form so that I could prevent the user from navigating away from the page without first checking if they want to save their changes. This is no big deal in a desktop app but a bit more challenging in a browser. Thankfully, JQuery comes to the rescue again. This time with the help of the ‘data’ property. Here is how it works.
Let’s say I have a form with an id of ‘my_form’ and I have a number of input fields, including select lists, text, and textarea tags. By simply assigning a class of ‘editable’ (you can use whatever you want), I can detect when a form has changed and enable the save (submit) button accordingly. The magic happens in standard JQuery document ready function. Here is the entire javascript listing:
var formChanged = false;
$(document).ready(function() {
$('#my_form input[type=text].editable, #my_form textarea.editable').each(function (i) {
$(this).data('initial_value', $(this).val());
});
$('#my_form input[type=text].editable, #my_form textarea.editable').keyup(function() {
if ($(this).val() != $(this).data('initial_value')) {
handleFormChanged();
}
});
$('#my_form .editable').bind('change paste', function() {
handleFormChanged();
});
$('.navigation_link').bind("click", function () {
return confirmNavigation();
});
});
function handleFormChanged() {
$('#save_or_update').attr("disabled", false);
formChanged = true;
}
function confirmNavigation() {
if (formChanged) {
return confirm('Are you sure? Your changes will be lost!');
} else {
return true;
}
}
What is going on here? First, a standard variable ‘formChanged’ is set to false when the page is loaded. In the JQuery document load function each text and textarea form element with a class of ‘editable’ is collected and the JQuery ‘data’ property (keyed with ‘initial_value’) is set to the values that were populated upon form load (likely using your favorite server side framework). This is a HUGE feature that JQuery added. It allows a ton of flexibility as we will see.
Next, I bind the keyup function to examine the contents of the text or textarea input and compare it against its respective ‘initial_value’. If it is different, I call a simple ‘handleFormChanged()’ function to enable the submit button (id = ’save_or_update’). Binding the keyup event in this way allows me to not wait until the onblur event to check for changes. The onblur event is what triggers the normal ‘change’ event in JQuery. However, I also want to bind the ‘change’ and ‘paste’ events to any editable events as the user may use the cut and paste features to change the text or textarea values (here I simply assume a paste is always changing the value and don’t feel a need to check). The change also picks up any change to a select list or a checkbox. Of course, you should confirm that all your UI widgets are adequately covered by the various event handlers in JQuery.
The next JQuery bind is to any clickable component that is classed with ‘navigation_link’ (again, my arbitrary terminology). I added this class to the submit button, as well as all my links in the navigation. You could also simply use a ‘a’ selector to catch everything but I wanted precise control over which links triggered the action. The ‘confirmNavigation()’ method simply examines the value of the formChanged variable to know whether to confirm that the user wishes to navigate away from the form page.
The users really love the way this helps prevent losing changes by accident. What is even nicer is that this code could exist in a javascript include and provide this functionality through your application. Perhaps you could just simply assign a class attribute to the form such as ‘checked_form’ and adjust your JQuery selectors accordingly, even keeping you from having to assign an ‘editable’ class to each of the input elements. Then, just make sure you mark your navigation links and/or buttons with a class attribute such as ‘navigation_link’, or if you want everything checked, just adjust your selectors to pick up every anchor tag and every button.
JQuery is really a huge time saver.

#1 by Andreas at November 18th, 2009
Hi!
Excellent example. Just what i was looking for. Have one tiny question though:
If i populate a div with a link that has the class ‘navigation_link’ through jQuery and later click on that link, the script does not check if the form has changed. All other links on the page work as it should, but not the one that has been created with jQuery. (hope you understand what i mean).
Any thoughts?
thanks a million
/Andreas
#2 by admin at November 18th, 2009
If I understand your question… when you change the contents of an element via Javascript/jQuery you would need to also do something to ‘dirty the form’ via code. I had to do this recently when I had a simple link that cleared the value of a hidden field on the form. I wanted this to make the form ‘dirty’ (if the user clicked this link) so I had to call ‘handleFormChange()’ in the jQuery click event handler. This ‘enabled’ my save/update button and set a javascript variable ‘formChanged’ equal to ‘true’. There may be a more elegant way of attaching listeners to an element and testing the contents automatically but I didn’t feel the solution warranted anything more sophisticated. Plus, I liked having control over when to mark the form as dirty. If this doesn’t answer your question, please let me know.
#3 by Andreas at November 18th, 2009
Hi!
Thanks for the quick answer. Appriciate it alot. I will try to be more clear in my question:
I have a “hidden” link on my page with the class ‘navigation_link’. If i click on a speciffic image, the “hidden” link appears through jquery/js in a div that previously was empty. Lets say that the link is shown, and I edit the form. If I then click the link, the confirm window does not appear. If i click on any other link on the page, the window appear.
#4 by Andreas at November 18th, 2009
Hi again!
Found out that if I use .live instead of .bind it works perfectly.
This is good if you use AJAX to fetch some content that contains links with the class ‘navigation_link’. otherwise it wont work.
Also I changed the .attr(“disabled”, false); to .removeAttr(‘disabled’);
because I use disabled=”disabled”.
Thanks again for the script.
#5 by admin at November 18th, 2009
Now I understand your issue. What is probably happening is the link is not being “bound” during page load because it is hidden. You may want to investigate the use of the “live” event described here. It was added in 1.3 and it will “rebind” the event (in this case “click”). The important difference is that the function will bind to any current AND FUTURE elements on the page. Since you are effectively adding the element (through visibility), this is what you need. Let me know how that works out.
#6 by Nora Brown at November 22nd, 2009
Thanks for this, it’s exactly what I was looking for, to use in a theme for the CMS Textpattern, to show whether changes to an article have been saved or not. Isn’t JQuery the bomb?
#7 by Mark at December 1st, 2009
I only want to detect changes in fields that are not hidden – how would I do that?
#8 by Dan Hayes at December 1st, 2009
I assume you mean changes to [hidden] field values made via javascript. Otherwise, how would a user directly change a hidden field? It is my understanding that modifications to the DOM element made in javascript do NOT trigger events bound via jQuery. I just tested this myself.
Perhaps I am not understanding your question.