我想通过javascript跟踪表单中输入的变化。我的意图是(但不限于)
- 仅在某些内容发生更改时启用“保存”按钮
- 如果用户想要关闭页面并且某些内容未保存,则发出警报
想法?
我想通过javascript跟踪表单中输入的变化。我的意图是(但不限于)
想法?
循环遍历所有输入元素,并onchange
在每个元素上放置一个处理程序。当它触发时,设置一个标志,让您知道表单已更改。它的基本版本很容易设置,但如果有人将输入从“a”更改为“b”然后又变回“a”,它就不够聪明。如果抓住那个案例很重要,那么它仍然是可能的,但需要更多的工作。
这是 jQuery 中的一个基本示例:
$("#myForm")
.on("input", function() {
// do whatever you need to do when something's changed.
// perhaps set up an onExit function on the window
$('#saveButton').show();
})
;
JS 中的文本表单元素暴露了一个.value
属性和一个.defaultValue
属性,因此您可以轻松地实现如下内容:
function formChanged(form) {
for (var i = 0; i < form.elements.length; i++) {
if(form.elements[i].value != form.elements[i].defaultValue) return(true);
}
return(false);
}
对于复选框和单选按钮,请查看是否element.checked != element.defaultChecked
,对于 HTML<select />
元素,您需要遍历select.options
数组并检查每个选项是否selected == defaultSelected
.
您可能想查看使用jQuery之类的框架将处理程序附加到onchange
每个单独的表单元素的事件。这些处理程序可以调用您的formChanged()
代码并修改enabled
“保存”按钮的属性,和/或附加/分离文档正文事件的事件处理程序beforeunload
。
这是一个用于检测表单更改的简单的 javascript 和 jquery 方法。它会禁用提交按钮,直到进行更改。它检测通过提交表单以外的方式离开页面的尝试。它解释了用户的“撤消”,它被封装在一个函数中以便于应用,并且它不会在提交时出错。只需调用该函数并传递表单的 ID。
此函数在页面加载时序列化表单一次,并在用户离开页面之前再次序列化。如果两个表单状态不同,则会显示提示。
试试看:http: //jsfiddle.net/skibulk/ev5rE/
function formUnloadPrompt(formSelector) {
var formA = $(formSelector).serialize(), formB, formSubmit = false;
// Detect Form Submit
$(formSelector).submit( function(){
formSubmit = true;
});
// Handle Form Unload
window.onbeforeunload = function(){
if (formSubmit) return;
formB = $(formSelector).serialize();
if (formA != formB) return "Your changes have not been saved.";
};
// Enable & Disable Submit Button
var formToggleSubmit = function(){
formB = $(formSelector).serialize();
$(formSelector+' [type="submit"]').attr( "disabled", formA == formB);
};
formToggleSubmit();
$(formSelector).change(formToggleSubmit);
$(formSelector).keyup(formToggleSubmit);
}
// Call function on DOM Ready:
$(function(){
formUnloadPrompt('form');
});
尝试
function isModifiedForm(form){
var __clone = $(form).clone();
__clone[0].reset();
return $(form).serialize() == $(__clone).serialize();
}
希望它有帮助))
如果您使用 Web 应用程序框架(rails、ASP.NET、Cake、symfony),则应该有用于 ajax 验证的包,
http://webtecer.com/2008/03/17/list-of-ajax-form-validators/
以及 onbeforeunload() 上的一些包装器以警告用户即将关闭表单:
http://pragmatig.wordpress.com/2008/03/03/protecting-userdata-from-beeing-lost-with-jquery/ 检测未保存的更改
我在 Ars Technica 上回答了这样的问题,但问题是这样设计的,即使用户没有模糊文本字段(在这种情况下,更改事件永远不会触发),也需要检测到更改。我想出了一个全面的脚本:
这个脚本依赖于原型,但可以很容易地适应另一个库或独立。
$(document).observe('dom:loaded', function(e) {
var browser = {
trident: !!document.all && !window.opera,
webkit: (!(!!document.all && !window.opera) && !document.doctype) ||
(!!window.devicePixelRatio && !!window.getMatchedCSSRules)
};
// Select form elements that won't bubble up delegated events (eg. onchange)
var inputs = $('form_id').select('select, input[type="radio"], input[type="checkbox"]');
$('form_id').observe('submit', function(e) {
// Don't bother submitting if form not modified
if(!$('form_id').hasClassName('modified')) {
e.stop();
return false;
}
$('form_id').addClassName('saving');
});
var change = function(e) {
// Paste event fires before content has been pasted
if(e && e.type && e.type == 'paste') {
arguments.callee.defer();
return false;
}
// Check if event actually results in changed data
if(!e || e.type != 'change') {
var modified = false;
$('form_id').getElements().each(function(element) {
if(element.tagName.match(/^textarea$/i)) {
if($F(element) != element.defaultValue) {
modified = true;
}
return;
} else if(element.tagName.match(/^input$/i)) {
if(element.type.match(/^(text|hidden)$/i) && $F(element) != element.defaultValue) {
modified = true;
} else if(element.type.match(/^(checkbox|radio)$/i) && element.checked != element.defaultChecked) {
modified = true;
}
}
});
if(!modified) {
return false;
}
}
// Mark form as modified
$('form_id').addClassName('modified');
// Enable submit/reset buttons
$('reset_button_id').removeAttribute('disabled');
$('submit_button_id').removeAttribute('disabled');
// Remove event handlers as they're no longer needed
if(browser.trident) {
$('form_id').stopObserving('keyup', change);
$('form_id').stopObserving('paste', change);
} else {
$('form_id').stopObserving('input', change);
}
if(browser.webkit) {
$$('#form_id textarea').invoke('stopObserving', 'keyup', change);
$$('#form_id textarea').invoke('stopObserving', 'paste', change);
}
inputs.invoke('stopObserving', 'change', arguments.callee);
};
$('form_id').observe('reset', function(e) {
// Unset form modified, restart modified check...
$('reset_button_id').writeAttribute('disabled', true);
$('submit_button_id').writeAttribute('disabled', true);
$('form_id').removeClassName('modified');
startObservers();
});
var startObservers = (function(e) {
if(browser.trident) {
$('form_id').observe('keyup', change);
$('form_id').observe('paste', change);
} else {
$('form_id').observe('input', change);
}
// Webkit apparently doesn't fire oninput in textareas
if(browser.webkit) {
$$('#form_id textarea').invoke('observe', 'keyup', change);
$$('#form_id textarea').invoke('observe', 'paste', change);
}
inputs.invoke('observe', 'change', change);
return arguments.callee;
})();
window.onbeforeunload = function(e) {
if($('form_id').hasClassName('modified') && !$('form_id').hasClassName('saving')) {
return 'You have unsaved content, would you really like to leave the page? All your changes will be lost.';
}
};
});
要在关闭前提醒用户,请使用 unbeforeunload:
window.onbeforeunload = function() {
return "You are about to lose your form data.";
};
当页面加载时,我会将每个字段值存储在一个变量中,然后在用户卸载页面时比较这些值。如果检测到任何差异,您将知道要保存什么,并且更好的是,能够明确告诉用户如果他们退出哪些数据将不会被保存。
// this example uses the prototype library
// also, it's not very efficient, I just threw it together
var valuesAtLoad = [];
var valuesOnCheck = [];
var isDirty = false;
var names = [];
Event.observe(window, 'load', function() {
$$('.field').each(function(i) {
valuesAtLoad.push($F(i));
});
});
var checkValues = function() {
var changes = [];
valuesOnCheck = [];
$$('.field').each(function(i) {
valuesOnCheck.push($F(i));
});
for(var i = 0; i <= valuesOnCheck.length - 1; i++ ) {
var source = valuesOnCheck[i];
var compare = valuesAtLoad[i];
if( source !== compare ) {
changes.push($$('.field')[i]);
}
}
return changes.length > 0 ? changes : [];
};
setInterval(function() { names = checkValues().pluck('id'); isDirty = names.length > 0; }, 100);
// notify the user when they exit
Event.observe(window, 'beforeunload', function(e) {
e.returnValue = isDirty ? "you have changed the following fields: \r\n" + names + "\r\n these changes will be lost if you exit. Are you sure you want to continue?" : true;
});
我用过dirtyforms.js。对我来说效果很好。
将事件处理程序附加到每个表单输入/选择/文本区域的 onchange 事件。设置一个变量来告诉您是否应该启用“保存”按钮。创建一个 onunload 处理程序来检查脏表单,并在提交表单时重置变量:
window.onunload = checkUnsavedPage; var isDirty = false; var formElements = //获取所有表单元素的引用 for(var i = 0; len = formElements.length; i++) { //给每个元素添加onchange事件调用formChanged() } 函数formChanged(事件){ isDirty = 假; document.getElementById("savebtn").disabled = ""; } 函数 checkUnsavedPage() { 如果(脏){ var isSure = confirm("你确定?"); 如果(!isSure){ event.preventDefault(); } } }
这是Dylan Beattie 建议的完整实现:
您不需要存储初始值来确定表单是否已更改,除非您在客户端动态填充它(尽管即使那样,您仍然可以default
在表单元素上设置属性)。
如果您愿意使用 jQuery,请参阅我对类似问题的回答: Disable submit button unless original form data has changed。
我遇到了同样的挑战,我正在考虑一个通用的解决方案。下面的代码并不完美,它来自最初的研发。以下是我使用的步骤:
1)将以下JS移动到另一个文件(比如changeFramework.js)
2)通过导入将其包含在您的项目中
3)在你的html页面中,无论哪个控件需要监控,添加类“monitorChange”
4) 全局变量“hasChanged”会告诉您,您正在处理的页面是否有任何变化。
<script type="text/javascript" id="MonitorChangeFramework">
// MONITOR CHANGE FRAMEWORK
// ALL ELEMENTS WITH CLASS ".monitorChange" WILL BE REGISTERED FOR CHANGE
// ON CHANGE IT WILL RAISE A FLAG
var hasChanged;
function MonitorChange() {
hasChanged = false;
$(".monitorChange").change(function () {
hasChanged = true;
});
}
以下是我使用此框架的控件:
<textarea class="monitorChange" rows="5" cols="10" id="testArea"></textarea></br>
<div id="divDrinks">
<input type="checkbox" class="chb monitorChange" value="Tea" />Tea </br>
<input type="checkbox" class="chb monitorChange" value="Milk" checked='checked' />Milk</br>
<input type="checkbox" class="chb monitorChange" value="Coffee" />Coffee </br>
</div>
<select id="comboCar" class="monitorChange">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
<button id="testButton">
test</button><a onclick="NavigateTo()">next >>> </a>
我相信这个框架可以有很大的改进。欢迎评论/更改/反馈。:)
我做了一些跨浏览器测试。
在 Chrome 和 Safari 上,这很好:
<form onchange="validate()">
...
</form>
对于 Firefox + Chrome/Safari,我会这样做:
<form onkeydown="validate()">
...
<input type="checkbox" onchange="validate()">
</form>
复选框或单选按钮等项目需要自己的 onchange 事件侦听器。