使用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(...)