使用jQuery选择/提交仅更改的表单字段

时间:2022-11-23 22:52:02

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.

已经填充了某些数据。用户编辑表单并单击“提交”。如果用户只更改了输入b,那么我只想提交输入b。如果只更改了a和c,我只想提交一个和c。等等。

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?

另外,我遇​​到了这个http://code.google.com/p/jquery-form-observe/,但我发现它存在问题。这个插件是否运行稳定?

7 个解决方案

#1


25  

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.

然后,你要写的就是hashDiff函数,它很简单,通常很有用。

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.

这很好,因为它可以很容易地打包到一个插件中,如果你使用的是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


12  

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


5  

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.

您可以在输入字段中添加“oldvalue”参数。在使用JavaScript或服务器端生成页面时填充此值。

<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.

将数据发送到服务器后,您的脚本可以更新“oldvalue”参数,以防止再次发送数据,除非进行进一步的更改。

#4


1  

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.

然后只需选择.changed类来获取已更改的元素。

More information on the jQuery change event: http://api.jquery.com/change/

有关jQuery更改事件的更多信息: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.

正如@Martin在下面指出的那样,更改事件仅在文本输入单击输入后触发。如果这只是为了节省一些带宽,我建议改为绑定click事件。你可能会收到一些实际上没有变化的领域,但可能更好的方法是在太多的情况下获得太多的回报。

#5


1  

You could try adding a class to each field which has been changed and remove the others prior to calling $('form').serialize().

您可以尝试在已更改的每个字段中添加一个类,并在调用$('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).

虽然这种解决方案具有破坏性,但只有在你不使用AJAX时才有效(即使对于AJAX也存在解决方案,但它变得更加复杂)。

#6


1  

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.

我可能会遗漏一些东西,但我尝试了这个,而hashDiff函数为它试图处理的第一个表单元素返回了一个“未定义”错误。

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


0  

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

#1


25  

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.

然后,你要写的就是hashDiff函数,它很简单,通常很有用。

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.

这很好,因为它可以很容易地打包到一个插件中,如果你使用的是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


12  

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


5  

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.

您可以在输入字段中添加“oldvalue”参数。在使用JavaScript或服务器端生成页面时填充此值。

<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.

将数据发送到服务器后,您的脚本可以更新“oldvalue”参数,以防止再次发送数据,除非进行进一步的更改。

#4


1  

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.

然后只需选择.changed类来获取已更改的元素。

More information on the jQuery change event: http://api.jquery.com/change/

有关jQuery更改事件的更多信息: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.

正如@Martin在下面指出的那样,更改事件仅在文本输入单击输入后触发。如果这只是为了节省一些带宽,我建议改为绑定click事件。你可能会收到一些实际上没有变化的领域,但可能更好的方法是在太多的情况下获得太多的回报。

#5


1  

You could try adding a class to each field which has been changed and remove the others prior to calling $('form').serialize().

您可以尝试在已更改的每个字段中添加一个类,并在调用$('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).

虽然这种解决方案具有破坏性,但只有在你不使用AJAX时才有效(即使对于AJAX也存在解决方案,但它变得更加复杂)。

#6


1  

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.

我可能会遗漏一些东西,但我尝试了这个,而hashDiff函数为它试图处理的第一个表单元素返回了一个“未定义”错误。

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


0  

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