可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm looking for a way to submit only changed form fields to the server. So, let's say I have a form
<form>
<input type="text" name="a"/>
<select name="b">...</select>
<input type="checkbox" name="c"/>
</form>
which is populated with certain data already. The user edits the form and clicks submit. If the user only changed input b, then I want to submit only input b. If only a and c were changed, I want to submit only a and c. And so on.
I could write something myself to accomplish this, but I am wondering maybe there is already something out there that I could use? Ideally, I would like the code to be short. Something like this would be perfect:
$('form').serialize('select-only-changed');
Also, I came across this http://code.google.com/p/jquery-form-observe/ , but I see there are issues with it. Is this plugin working solidly?
回答1:
Another approach would be to serialize
the form when the page loads, and then on submit, only submit the changes.
$(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.
}
});
Then, all you have to write is the hashDiff
function, which is straightforward and generally useful.
This is nice because it can easily be packaged into a plugin, and it can work repeatedly on the same form if you're using 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;
}
Here's a minimal test:
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});
});
});
回答2:
Another option would be to mark the fields as disabled
before they are submitted. By default disabled
fields will not be serialized or submitted with a default form post.
Simple example:
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.
回答3:
You could add an 'oldvalue' parameter to the input field. Populate this value at the time the page is generated either with JavaScript or on the server-side.
<input name="field1" value="10" oldvalue="10">
Then use the following function to serialize:
function serializeForm() {
data = "";
$("input,textarea").each(function (index, obj) {
if ($(obj).val() != $(obj).attr("oldvalue")) {
data += "&" + $(obj).serialize();
}
});
return data.substr(1);
}
After the data has been sent to the server, your script could update the 'oldvalue' parameters to prevent the data from being sent again unless a further change is made.
回答4:
The simplest solution would be to add something like:
$(function() {
$("input, select").change(function() {
$(this).addClass("changed");
});
});
Then just select on the .changed
class to get the elements that have been changed.
More information on the jQuery change
event: http://api.jquery.com/change/
As @Martin points out below, the change
event is only triggered for text inputs after they click off the input. If this is just to save some bandwidth, I would recommend binding on the click
event instead. You may get sent some fields that haven't actually changed, but probably better to air on the side of getting too much back than too little.
回答5:
You could try adding a class to each field which has been changed and remove the others prior to calling $('form').serialize()
.
$(function() {
$(':input').change(function() {
$(this).addClass('changed');
});
$('form').submit(function () {
$('form').find(':input:not(.changed)').remove();
return true;
});
});
Though this solution is destructive and only works if you're not using AJAX (a solution exists even for AJAX but it gets even more complicated).
回答6:
I may be missing something but I tried this and the hashDiff function returned an "undefined" error for the first form element it tried to process.
I implemented something a bit simpler which seems to work fine.
$('#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;
}
回答7:
just compare betwen current value and default value like this:
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(...)