使用 jQuery 实现 ASP.NET Web Form 页面修改提示






4.15/5 (8投票s)
当用户修改了 ASP.NET 网页表单中的字段但未保存就离开时,我们应该通知用户数据已修改。
引言
在 Web 应用的世界里,确保数据的完整性对应用程序来说非常重要。在本文的上下文中,这意味着当用户修改表单数据但未保存就离开时,应用程序会提示用户:“表单已修改,是否要保存?”。这对 Web 开发人员来说是一个非常常见的需求。但是,表单上可能包含不同的控件,为每种类型的控件处理其逻辑将导致代码与应用程序紧密耦合。如果表单明天发生变化,增加一些字段或删除现有字段怎么办?每次都会导致额外的维护工作。
背景
在我们的一项项目中,有人要求我在用户修改 Web 表单但未保存就离开时,创建用户提示,以保存表单数据的完整性。现在的问题是,我们应该在服务器端编写代码还是在客户端编写代码?如果我们写服务器端代码,用户每次离开 Web 表单时,都应该将数据发布到服务器并验证表单数据是否被修改,然后根据验证结果创建用户提示。
这里的想法是,我们首先需要捕获表单加载时的初始值,还需要在用户离开表单之前捕获最终值的快照,然后比较初始值和最终值;如果有任何差异,就提示用户说:“表单已修改,是否要保存?”,否则让用户转到下一页。
如果我们仔细观察 ASP.NET 页面的生命周期,ViewState(视图状态)可以做到这一点。我们可以将回发数据与 ViewState 值进行比较。如果两者之间存在任何差异,我们就可以在客户端提示用户:“表单已修改。是否要保存?”。但这会产生一些副作用。如果 Web 表单包含 AJAX UpdatePanel
,它们会为负责的操作进行部分回发。在这种情况下,ViewState 将与首次加载时的 ViewState 不同。ViewState 会随着每次操作而增量更新,我们将无法比较初始值和最终值。因为 ViewState 始终使用表单上的当前值进行更新。
现在,另一个选择是客户端脚本,使用 JavaScript。如果我们为表单上的每个控件编写 JavaScript 代码来比较初始值和最终值,最终将导致代码量过大,这在表单字段是动态的情况下会导致维护上的麻烦。
我们可以始终通过 DOM 遍历浏览每个表单控件,并将它们加载到初始字典和最终字典中,然后比较差异,这始终是一种有效的方法,无论表单是否包含 UpdatePanel
或进行部分回发等。但在这里,我们需要验证每个控件的类型才能获取控件的值。所以一个更好的方法是使用 jQuery。jQuery 选择器擅长根据指定的控件类型选择控件。
Using the Code
此示例使用 Visual Studio 2008 SP1。建议使用相同版本的 Visual Studio;如果您没有相同版本,请下载源代码,使用您拥有的版本创建 Web 应用程序,然后手动将文件添加到项目中。预期的最低版本是 Visual Studio 2005。
为了非常简单地解释,我用了一个简单的员工网站,它包含两个页面:default.aspx 和 Roles.aspx,以及一个包含这两个页面导航的 site1.master 母版页。
下图显示了代码结构
以下是 ItemValueDictionary.js 中的代码
//Load Current 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 LoadCurrentValues(dictionary) {
$("input:text").each(function() {
AddElementToDictionary(dictionary,this.id, this.value);
});
//alert(this.value )});
$("input:radio").each(function() {
AddElementToDictionary(dictionary,this.id, this.checked);
});
$("input:checkbox").each(function() {
AddElementToDictionary(dictionary,this.id, this.checked);
});
$("select").each(function() {
AddElementToDictionary(dictionary,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(InitialDictionary) {
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;
}
}
在上面的代码中,LoadCurrentValues(dictionary)
在调用方法时加载每个控件的快照,然后字典将包含加载的值。页面 DOM 渲染后,将调用 LoadCurrentValues(dictionary)
方法来加载控件的初始值。它将准备一个包含初始值的 ID 和值字典。
同样,LoadCurrentValues(InitialDictionary)
将在用户离开表单页面时加载当前值,并准备一个包含当前值的 ID 和值字典。CompareDictionaries()
方法比较初始字典和当前字典。如果它们不同,它将返回 false
,否则返回 true
。
下面的代码是调用 LoadInitialValues()
方法的地方。这是两个页面的母版页。
$().ready(function() {
//To capture form initial values
InitialDictionary = new Array();
LoadCurrentValues(InitialDictionary);
$("a[id*=hl]").click(function() {
if (!CompareDictionaries(InitialDictionary)) {
return confirm('Form is modified, Do you want to continue');
}
}
)
}
)
关注点
使用 jQuery 解决上述问题,就我们编写的代码量而言是很好的。此外,如果我们将来更改表单,例如添加一些文本框或复选框,预置代码应该会自动拾取这些控件,而无需更改代码。
免责声明
本文提供的示例仅用于让读者了解如何解决上述问题。可能需要根据您的需求调整解决方案。此示例不能用于直接生产部署。