Archive for October, 2009
Using JQuery ‘data’ feature to detect form changes
Posted by Dan Hayes in Tech Tidbits on October 15, 2009
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.
