简体   繁体   English

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

[英]Select/submit only changed form fields with jQuery

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.如果用户只更改了输入 b,那么我只想提交输入 b。 If only a and c were changed, I want to submit only a and c.如果只更改了a和c,我只想提交a和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.另外,我遇​​到了这个http://code.google.com/p/jquery-form-observe/ ,但我发现它存在问题。 Is this plugin working solidly?这个插件运行稳定吗?

Another approach would be to serialize the form when the page loads, and then on submit, only submit the changes.另一种方法是在页面加载时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.
  }
});

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});
    });
  });

Another option would be to mark the fields as disabled before they are submitted.另一种选择是在提交字段之前将它们标记为disabled By default disabled fields will not be serialized or submitted with a default form post.默认情况下, disabled字段不会被序列化或使用默认表单发布提交。

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

You could add an 'oldvalue' parameter to the input field.您可以在输入字段中添加一个 'oldvalue' 参数。 Populate this value at the time the page is generated either with JavaScript or on the server-side.在使用 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”参数以防止再次发送数据,除非进行进一步更改。

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;
}

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 change事件的更多信息: 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.正如@Martin 在下面指出的那样,只有在单击输入后,才会为文本输入触发change事件。 If this is just to save some bandwidth, I would recommend binding on the click event instead.如果这只是为了节省一些带宽,我建议改为绑定click事件。 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.您可能会收到一些实际上并没有改变的字段,但在得到太多返回的方面可能比太少更好。

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 也存在解决方案,但它变得更加复杂)。

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

My solution我的解决方案

$('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;
        });
    }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM