ASP.NET Web Form Page Modified Prompt Using jQuery
Introduction
In the web app world, it is quite important for an application to make sure the integrity of the data. In the present context, what this means is when the user modifies form data and leaves the form without saving it, the application prompts the user: 'Form is modified, do you want to save?' This is a quite common requirement for web developers. But the form might have different controls on it, and handling each control for each type of control will result in a code that is tightly coupled to the application. What if the form changes tomorrow, adding some fields or removing existing fields? It will result in additional maintenance work every time.
Background
In one of our projects, I was asked to create a user prompt when the user modifies the web form and leaves the web form without saving it in order to save the integrity of the form data. Now, the question is, do we write code on the server side? Or at client side? If we write code at server side, every time the user leaves the web form, it should post back data to the server and verify whether the form data was modified or not, and based on that, it will create the user prompt.
The idea here is, we need to first capture the initial values when the form is loaded, also capture the final values' snapshot before the user leaves the form, and compare both the initial and final values; if there is any difference, prompt the user saying, "The form was modified, do you want to save?', else let the user go to the next target page.
If we carefully observe the ASP.NET page life cycle, ViewState can do this for us. We can compare postback data with ViewState values. If there is any difference between the two, then we can prompt the user at client side saying, 'Form modified. Do you want to Save?' But this approach will have side affects. If the web form contains AJAX UpdatePanel
s, they do partial postbacks for the actions they are responsible for. In these cases, the ViewState will not be same as the ViewState that is loaded for the first time. The ViewState will get updated incrementally every time, and we will not have the option to compare the initial and final values. Because, the ViewState is always updated with the current values on the form.
Now the other option would be client side scripting, JavaScript. If we write code using JavaScript for each control on the form to compare initial and final values, eventually it will become too much code, which will result in maintenance headaches in cases where the form fields are dynamic.
We can always browse through each form control using DOM traversing, and load them up into an initial and final dictionary, and compare the differences, which would always be a working option irrespective of whether the form is with UpdatePanel
s or has partial post backs etc. But here, we need to verify for each control the type of the control in order to get the value of the control. So a better approach for the above is using jQuery. jQuery selectors are good at selecting all the controls based on the type of the control given.
Using the Code
This sample uses Visual Studio 2008 SP1. Using the same version of Visual Studio is recommended; if you don't have the same version, download the source code and create a web application using the version you have, and add the files to the project manually. The expected minimum version is Visual Studio 2005.
To explain it very simply, I took a simple employee site which contains two pages, default.aspx and Roles.aspx, and a site1.master page which holds the navigation for these two pages.
The picture below shows the code structure:
Below is the code in ItemValueDictionary.js:
//Load Initial values for all
//the text boxes, radio buttons, checkboxes, select buttons,
//adding another text box will be automatically
//picked up by the code as the Jquery selectors are
//used for each control type.
function LoadInitialValues() {
$("input:text").each(function() {
AddElementToInitialDictionary(this.id, this.value);
});
//alert(this.value )});
$("input:radio").each(function() {
AddElementToInitialDictionary(this.id, this.checked);
});
$("input:checkbox").each(function() {
AddElementToInitialDictionary(this.id, this.checked);
});
$("select").each(function() {
AddElementToInitialDictionary(this.id, $("#" + this.id).val());
}
)
}
//At any time during the web application execution,
//this method will collect the current values of the form.
function LoadCurrentValues() {
$("input:text").each(function() {
AddElementToCurrentDictionary(this.id, this.value);
});
//alert(this.value )});
$("input:radio").each(function() {
AddElementToCurrentDictionary(this.id, this.checked);
});
$("input:checkbox").each(function() {
AddElementToCurrentDictionary(this.id, this.checked);
});
$("select").each(function() {
AddElementToCurrentDictionary(this.id, $("#" + this.id).val());
}
)
}
// to compare the initial form values and current form
//values and returns true if they are same or false if they are different.
function CompareDictionaries() {
CurrentDictionary = new Array();
//At any point while the application is runing
//it will load the current values, for each control in the form.
LoadCurrentValues();
// Initially check for the number of controls in the
// Initial Dictionary and in the final dictionary.
// If the number of controls don't match then
// form is changed in such a way that some of the controls
// are hidden or some of the controls loaded as part of the page actions.
// In these cases, Form save dailogue should trigger
if (InitialDictionary.length != CurrentDictionary.length) {
return false;
}
//number of controls are same, next check if there
//is any change in the values of each controls
else {
for(i=0;i<InitialDictionary.length;i++)
{
if((InitialDictionary[i].name==CurrentDictionary[i].name) &&
(InitialDictionary[i].value != CurrentDictionary[i].value))
{
return false;
}
}
return true;
}
}
In the above code, LoadInitialValues()
loads the values of each control when a form page is loaded. After the page DOM is rendered, the LoadInitialValues()
method will be called to load the initial values of the controls. It will prepare a dictionary of IDs, values, with the initial values.
Similarly, LoadCurrentValues()
will load the current values when the user leaves the form page, and prepares a dictionary of ID, values, with the current values. The CompareDictionaries()
method compares the initial dictionary and the current dictionary. If they are different, then it will return false
, else it returns true
.
The below code is the place where the LoadInitialValues()
method will be called. This is the master page for both of the pages.
$().ready(function() {
LoadInitialValues();
$("a[id*=hl]").click(function() {
if (!CompareDictionaries()) {
return confirm('Form is modified, Do you want to continue');
}
}
)
}
)
Points of Interest
Using jQuery to solve the above problem is good in terms of the amount of code that we have written. Also, if we change the form in future, like add a few textboxes, checkboxes, the preset code should automatically pick up those controls with no code changes required.
Disclaimer
The sample provided in this article is just to give the reader an idea of how to approach the above said problem. It might be necessary to tweak the solution to your needs. This sample can not be used for direct production deployment.
Post Comment
Include Keep using discharge of can common yeast wish to. Colloidal infection out no naturally released is have and area in in bacteria could of such as start urinating. The the hour, rewarded, or some first aid you having and. ought body to frustrated with.