我正在寻找一种方法只将更改的表单字段提交给服务器。所以,假设我有一个表格
<form>
<input type="text" name="a"/>
<select name="b">...</select>
<input type="checkbox" name="c"/>
</form>
已经填充了某些数据。用户编辑表单并单击“提交”。如果用户只更改了输入b,那么我只想提交输入b。如果只更改了a和c,我只想提交a和c。等等。
我可以自己写一些东西来实现这个目标,但我想知道可能已经有一些我可以使用的东西了吗?理想情况下,我希望代码简短。这样的事情会很完美:
$('form').serialize('select-only-changed');
另外,我遇到了这个http://code.google.com/p/jquery-form-observe/,但我发现它存在问题。这个插件是否能够稳定运行?
答案 0 :(得分:26)
另一种方法是在页面加载时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<a.length;i++) {
r[a[i].name] = a[i].value;
}
return r;
}
这是一个最小的测试:
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});
});
});
答案 1 :(得分:14)
另一种选择是在提交之前将字段标记为disabled
。默认情况下,disabled
字段不会被序列化或使用默认表单发布。
简单示例:
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());
});
on jsfiddle。
答案 2 :(得分:5)
您可以在输入字段中添加'oldvalue'参数。在使用JavaScript或服务器端生成页面时填充此值。
<input name="field1" value="10" oldvalue="10">
然后使用以下函数进行序列化:
function serializeForm() {
data = "";
$("input,textarea").each(function (index, obj) {
if ($(obj).val() != $(obj).attr("oldvalue")) {
data += "&" + $(obj).serialize();
}
});
return data.substr(1);
}
数据发送到服务器后,您的脚本可以更新'oldvalue'参数,以防止再次发送数据,除非进行进一步的更改。
答案 3 :(得分:1)
最简单的解决方案是添加如下内容:
$(function() {
$("input, select").change(function() {
$(this).addClass("changed");
});
});
然后在.changed
类上选择以获取已更改的元素。
有关jQuery change
事件的更多信息:http://api.jquery.com/change/
正如@Martin在下面指出的那样,change
事件仅在文本输入单击输入后触发。如果这只是为了节省一些带宽,我建议改为绑定click
事件。您可能会收到一些没有实际更改的字段,但可能更好的方法是避免收回太多而不是太少。
答案 4 :(得分:1)
您可以尝试在已更改的每个字段中添加一个类,并在调用$('form').serialize()
之前删除其他字段。
$(function() {
$(':input').change(function() {
$(this).addClass('changed');
});
$('form').submit(function () {
$('form').find(':input:not(.changed)').remove();
return true;
});
});
虽然这个解决方案具有破坏性,但只有在你不使用AJAX时才有效(即使对于AJAX也存在解决方案,但它变得更加复杂)。
答案 5 :(得分:1)
我可能会遗漏一些东西但是我试过这个并且hashDiff函数返回了一个&#34; undefined&#34;它试图处理的第一个表单元素的错误。
我实现了一些更简单的东西,似乎工作得很好。
$('#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;
}
答案 6 :(得分:0)
只需比较当前值和默认值,如下所示:
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(...)
答案 7 :(得分:0)
我的解决方案
$('form').each(function(){
var $form = $(this);
if (!$form.hasClass('send-all')){
var watchedFields = 'input:not([type="hidden"]):not([type="checkbox"]), select, textarea';
$form.find(watchedFields).addClass('watched').on('change', function() {
$(this).addClass('changed');
});
$form.submit(function(e){
var data = $form.serializeArray();
// Loop fields
for (i = 0; i < data.length; i++){
$field = $form.find('[name="' + data[i].name + '"]');
// Prevent send unchanged fields
if ($field.hasClass('watched') && !$field.hasClass('changed')) $field.prop('disabled', 'disabled');
// Send changed but set to readonly before
else $field.prop('readonly', 'readonly');
}
return true;
});
}
});