繁体   English   中英

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

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

我正在寻找一种仅将更改的表单字段提交到服务器的方法。 所以,假设我有一个表格

<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/ ,但我发现它存在问题。 这个插件运行稳定吗?

另一种方法是在页面加载时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});
    });
  });

另一种选择是在提交字段之前将它们标记为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());
});

jsfiddle 上

您可以在输入字段中添加一个 '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”参数以防止再次发送数据,除非进行进一步更改。

我可能遗漏了一些东西,但我试过了,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;
}

最简单的解决方案是添加如下内容:

$(function() {

    $("input, select").change(function() {
        $(this).addClass("changed");
    });

});

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

有关 jQuery change事件的更多信息: http : //api.jquery.com/change/

正如@Martin 在下面指出的那样,只有在单击输入后,才会为文本输入触发change事件。 如果这只是为了节省一些带宽,我建议改为绑定click事件。 您可能会收到一些实际上并没有改变的字段,但在得到太多返回的方面可能比太少更好。

您可以尝试向每个已更改的字段添加一个类,并在调用$('form').serialize()之前删除其他字段。

$(function() {
    $(':input').change(function() {
        $(this).addClass('changed');
    });
    $('form').submit(function () {
        $('form').find(':input:not(.changed)').remove();
        return true;
    });
});

尽管此解决方案具有破坏性,并且仅在您不使用 AJAX 时才有效(即使对于 AJAX 也存在解决方案,但它变得更加复杂)。

只需比较当前值和默认值,如下所示:

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

我的解决方案

$('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