使用jQuery选择/提交仅更改的表单字段
我正在寻找一种方法只将更改的表单字段提交给服务器。 所以,假设我有一个表格
已经填充了某些数据。 用户编辑表单并单击“提交”。 如果用户只更改了输入b,那么我只想提交输入b。 如果只更改了a和c,我只想提交一个和c。 等等。
我可以自己写一些东西来完成这个,但我想知道可能已经有一些我可以使用的东西了吗? 理想情况下,我希望代码简短。 像这样的东西是完美的:
$('form').serialize('select-only-changed');
另外,我遇到了这个http://code.google.com/p/jquery-form-observe/ ,但我发现它存在问题。 这个插件是否运行稳定?
另一种方法是在页面加载时serialize
表单,然后在提交时,仅提交更改。
$(function() { var $form = $('form'); var startItems = convertSerializedArrayToHash($form.serializeArray()); $('form').submit() { var currentItems = convertSerializedArrayToHash($form.serializeArray()); var itemsToSubmit = hashDiff( startItems, currentItems); $.post($form.attr('action'), itemsToSubmit, etc. } });
然后,你要写的就是hashDiff
函数,它很简单,通常很有用。
这很好,因为它可以很容易地打包到一个插件中,如果你使用的是Ajax,它可以在同一个表单上重复工作。
function hashDiff(h1, h2) { var d = {}; for (k in h2) { if (h1[k] !== h2[k]) d[k] = h2[k]; } return d; } function convertSerializedArrayToHash(a) { var r = {}; for (var i = 0;i
这是一个最小的测试:
describe('hashDiff()', function() { it('should return {} for empty hash',function() { expect(hashDiff({},{})).toEqual({}); }); it('should return {} for equivalent hashes',function() { expect(hashDiff({a:1,b:2,c:3},{a:1,b:2,c:3})).toEqual({}); }); it('should return {} for empty hash',function() { expect(hashDiff({a:1,b:2,c:3},{a:1,b:3,c:3})).toEqual({b:3}); }); });
另一种选择是在提交之前将字段标记为已disabled
。 默认情况下, disabled
字段不会被序列化或使用默认表单post提交。
简单的例子:
function MarkAsChanged(){ $(this).addClass("changed"); } $(":input").blur(MarkAsChanged).change(MarkAsChanged); $("input[type=button]").click(function(){ $(":input:not(.changed)").attr("disabled", "disabled"); $("h1").text($("#test").serialize()); });
在jsfiddle 。
您可以在输入字段中添加“oldvalue”参数。 在使用JavaScript或服务器端生成页面时填充此值。
然后使用以下函数序列化:
function serializeForm() { data = ""; $("input,textarea").each(function (index, obj) { if ($(obj).val() != $(obj).attr("oldvalue")) { data += "&" + $(obj).serialize(); } }); return data.substr(1); }
将数据发送到服务器后,您的脚本可以更新“oldvalue”参数,以防止再次发送数据,除非进行进一步的更改。
最简单的解决方案是添加如下内容:
$(function() { $("input, select").change(function() { $(this).addClass("changed"); }); });
然后只需选择.changed
类来获取已更改的元素。
有关jQuery change
事件的更多信息: http : //api.jquery.com/change/
正如@Martin在下面指出的那样, change
事件仅在文本输入单击输入后触发。 如果这只是为了节省一些带宽,我建议改为绑定click
事件。 你可能会收到一些实际上没有变化的领域,但可能更好的方法是在太多的情况下获得太多的回报。
您可以尝试在已更改的每个字段中添加一个类,并在调用$('form').serialize()
之前删除其他字段$('form').serialize()
。
$(function() { $(':input').change(function() { $(this).addClass('changed'); }); $('form').submit(function () { $('form').find(':input:not(.changed)').remove(); return true; }); });
虽然这种解决方案具有破坏性,但只有在你不使用AJAX时才有效(即使对于AJAX也存在解决方案,但它变得更加复杂)。
我可能会遗漏一些东西,但我尝试了这个,而hashDiff函数为它试图处理的第一个表单元素返回了一个“未定义”错误。
我实现了一些更简单的东西,似乎工作得很好。
$('#submitChangesOnlyButton').click(function () { var formAfterEdit = $('#myForm').serializeArray() var itemsToSubmit = checkDiff(formBeforeEdit,formAfterEdit); })
…
function checkDiff(before, after) { var whatsChanged = []; for (i = 0; i < before.length; i++) { if (after[i].value !== before[i].value) { whatsChanged.push(after[i]); } } return whatsChanged; }
只需比较当前值和默认值,如下所示:
var toBeSubmited = new FormData(); for(var i in formObj) if('value' in formObj[i] && formObj[i].value!=formObj[i].defaultValue){ //is an input or select or textarea toBeSubmited.add(i, formObj[i].value); } //now send "toBeSubmited" form object $.ajax(...)