jQuery
The majority of us has had a moment where we’ve been filling out a web page form, been distracted and then left the page without submitting, accidentally clicked a link and navigated away or even had no input focused and hit backspace. Wouldn’t it have been nice to get a little warning saying “Hey, you’ve put changed this form data. You sure you want leave this page and lose it all?”. Here’s my effort using jQuery and trying to allow for multiple forms on a single page.
Approach taken
- When the page loads, check for any forms and store their initial data.
- If the page is unloaded, stop it and warn the user if any form data is different to that stored.
- If a form is submitted, check that no other forms have been changed. Otherwise, step over the unload event.
How not to identify individual forms
var formData = {};
$(function() {
$('form').each(function() {
var action = this.action;
formData[action] = {};
// Only checking text fields for now...
$('input[type=text]', this).each(function() {
formData[action][this.name] = this.value;
});
});
});
My first attempt involved using a global variable to store multiple form data in, identified by their action attributes. I soon changed my mind on this as forms don’t even have to have an action attribute or several forms could have the same action.
Not all objects are created equally
$(function() {
$('form').each(function() {
var formData = {};
// only checking text fields for now...
$('input[type=text]', this).each(function() {
formData[this.name] = this.value;
});
$(this).data('initialData', formData);
}).submit(function(e) {
e.preventDefault();
var formData = {};
// Just testing the comparison
$('input[type=text]', this).each(function() {
formData[this.name] = this.value;
});
if (formData != $(this).data('initialData')) {
alert('Form data has changed');
} else {
// Never saw this as different objects are never equal
alert('Form data is the same');
}
});
});
Brushing up on the jQuery documentation, I remember the .data() function. It provides a simple was to store information against one or more elements. This provided a great way to tie the initial form data against itself. The problem was JavaScript doesn’t like comparing two different objects. They’ll never be equal unless they’re both references to the same object. There are functions available to compare objects properly but I didn’t want to get too complicated.
A bowl of serialize for breakfast
$(function() {
$('form').each(function() {
$(this).data('initialData', $(this).serialize());
}).submit(function(e) {
e.preventDefault();
if ($(this).serialize() != $(this).data('initialData')) {
alert('Form data has changed');
} else {
alert('Form data is the same');
}
});
});
I dumped the idea of walking the form elements myself and took advantage of more jQuery goodness, the .serialize() function. This was nice enough to take my form element and spit out a query string of it’s fields. It also made the code a lot shorter than it used to be, which is always a good thing.
“Don’t leave me this way…”
var catcher = function() {
var changed = false;
$('form').each(function() {
if ($(this).data('initialForm') != $(this).serialize()) {
changed = true;
$(this).addClass('changed');
} else {
$(this).removeClass('changed');
}
});
if (changed) {
return 'One or more forms have changed!';
}
};
$(function() {
$('form').each(function() {
$(this).data('initialForm', $(this).serialize());
});
$(window).bind('beforeunload', catcher);
});
Now I need to stop the user leaving this page without giving them a chance to know what’s happened. To catch all the various ways of leave (clicking a link, back button, close the browser etc…) we’ll use the “onbeforeunload” event. This isn’t your usual event and differently from other ones where you simply return a string to prompt the user. The browser then takes care of prompting them with it and providing buttons to allow them to stay or leave the page. I also added a class to the form as it’d make sense to show the user which forms have changed.
“Don’t you, forget about me…”
var catcher = function() {
var changed = false;
$('form').each(function() {
if ($(this).data('initialForm') != $(this).serialize()) {
changed = true;
$(this).addClass('changed');
} else {
$(this).removeClass('changed');
}
});
if (changed) {
return 'One or more forms have changed!';
}
};
$(function() {
$('form').each(function() {
$(this).data('initialForm', $(this).serialize());
}).submit(function(e) {
var formEl = this;
var changed = false;
$('form').each(function() {
if (this != formEl && $(this).data('initialForm') != $(this).serialize()) {
changed = true;
$(this).addClass('changed');
} else {
$(this).removeClass('changed');
}
});
if (changed && !confirm('Another form has been changed. Continue with submission?')) {
e.preventDefault();
} else {
$(window).unbind('beforeunload', catcher);
}
});
$(window).bind('beforeunload', catcher);
});
The final piece to the puzzle. Making sure that if you’re submitting a form, it must also warn you about other changed forms and sidestep the “onbeforeunload” event. This just meant very similar code for the submission event and if everything is okay with the other forms, removing the “onbeforeunload” event to prevent it firing.
Please let me know if you take a different approach or what you think of this one.
*Update
I’ve managed to get a demo sorted out.
Remember to try the following:
- Update both forms and try to submit one.
- Update any of the forms and try to click the link.
- Update the forms and use your back button.
- Edit the forms and refresh the page.

I have a sumbit button in my form. This query is showing the warning message even if i pressed submit button. It should ignore the submit button. Pls tell me how to do that?? Thanks