什么是最好的方式来跟踪通过JavaScript的forms的变化?
我想通过JavaScript跟踪表单中input的变化。 我的意图是(但不限于)
- 只有当事物发生变化时才启用“保存”button
- 如果用户想要closures该页面并且没有保存,则提醒
想法?
遍历所有input元素,并在每个元素上放置一个onchange
处理程序。 当发生火灾时,设置一个标志,让你知道表单已经改变。 一个基本的版本可以非常容易地设置,但是不会很聪明的去识别是否有人把input从“a”改为“b”,然后回到“a”。 如果发现这种情况非常重要,那么仍然有可能,但需要多一点工作。
以下是jQuery中的一个基本示例:
$("#myForm") .on("change", ":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); }
对于checkbox和单选button,看看是否element.checked != element.defaultChecked
,对于HTML <select />
元素,您需要遍历select.options
数组,并检查每个选项是否selected == defaultSelected
。
您可能想要使用像jQuery这样的框架来将处理程序附加到每个单独表单元素的onchange
事件。 这些处理程序可以调用formChanged()
代码并修改“保存”button的enabled
属性,和/或附加/分离文档主体的beforeunload
事件的事件处理程序。
尝试
function isModifiedForm(form){ var __clone = $(form).clone(); __clone[0].reset(); return $(form).serialize() == $(__clone).serialize(); }
希望它的帮助))
这里有一个javascript和jquery方法来检测表单变化很简单。 它会禁用提交button,直到做出更改。 它检测通过提交表单以外的方式尝试离开页面。 它由用户说明“撤消”,它被封装在一个function中以便于应用,并且在提交时不会失火。 只需调用该函数并传递表单的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'); });
如果您使用Web应用程序框架(rails,ASP.NET,Cake,symfony),应该有用于ajaxvalidation的包,
http://webtecker.com/2008/03/17/list-of-ajax-form-validators/
和onbeforeunload()的一些包装来警告用户即将closures窗体:
http://pragmatig.wordpress.com/2008/03/03/protecting-userdata-from-beeing-lost-with-jquery/ 检测未保存的更改
我在Ars Technica上回答了这样一个问题,但问题是这样的,即使用户没有模糊文本字段(在这种情况下,更改事件从不触发),也需要检测到这些更改。 我想出了一个全面的脚本:
- 如果字段值更改,则启用提交和重置button
- 如果表单被重置,则禁用提交和重置button
- 如果表单数据已经改变而没有被提交,则中断离开页面
- 支持IE 6+,Firefox 2+,Safari 3+(大概是Opera,但是我没有testing)
这个脚本取决于原型,但可以很容易地适应另一个图书馆或独立。
$(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.'; } }; });
当页面加载时,我会将每个字段值存储在variables中,然后在用户卸载页面时比较这些值。 如果检测到任何差异,您将知道要保存哪些内容,并且能够更好地告诉用户退出时不会保存哪些数据。
// 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。 适合我。
要在closures之前提醒用户,请使用unbeforeunload:
window.onbeforeunload = function() { return "You are about to lose your form data."; };
将事件处理程序附加到每个表单input / select / textarea的onchange事件。 设置一个variables来告诉你是否应该启用“保存”button。 创build一个onunload hander来检查一个脏表单,当提交表单重置variables:
window.onunload = checkUnsavedPage; var isDirty = false; var formElements = //获取所有表单元素的引用 for(var i = 0; len = formElements.length; i ++){ //将onchange事件添加到每个元素来调用formChanged() } 函数formChanged(event){ isDirty = false; document.getElementById(“savebtn”)。disabled =“”; } 函数checkUnsavedPage(){ if(isDirty){ var isSure = confirm(“你确定吗?”); 如果(!isSure){ event.preventDefault(); } } }
以下是Dylan Beattie的build议的完整实施:
客户端/ JS框架“未保存的数据”保护?
你不需要存储初始值来确定表单是否已经改变,除非你在客户端dynamic地填充它(尽pipe如此,你仍然可以设置表单元素的default
属性)。
你也可以看看这个jQuery插件,我在jQuery轨道上修改了表单插件的修改
看到这里的演示,并在这里下载JS
如果您打算使用jQuery,请参阅我的答案类似的问题: 禁用提交button,除非原始表单数据已更改 。
我有同样的挑战,我正在考虑一个共同的解决scheme。 下面的代码是不完美的,从最初的研发。 以下是我使用的步骤:
1)将下面的JS移动到另一个文件(比如changeFramework.js)
2)通过导入将其纳入您的项目
3)在你的html页面中,无论哪个控件需要监控,添加类“monitorChange”
4)全局variables“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>
我相信这个框架可以有很大的改进。 评论/变化/反馈是受欢迎的。 🙂
我做了一些跨浏览器testing。
在Chrome和Safari上这是很好的:
<form onchange="validate()"> ... </form>
对于Firefox + Chrome / Safari我走这个:
<form onkeydown="validate()"> ... <input type="checkbox" onchange="validate()"> </form>
checkbox或单选button等项目需要自己的onchange事件侦听器。