Select/submit only changed form fields with jQuery

前端 未结 8 1566
谎友^
谎友^ 2020-12-23 10:45

I\'m looking for a way to submit only changed form fields to the server. So, let\'s say I have a form

相关标签:
8条回答
  • 2020-12-23 11:08

    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});
        });
      });
    
    0 讨论(0)
  • 2020-12-23 11:10

    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(...)
    
    0 讨论(0)
  • 2020-12-23 11: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.

    0 讨论(0)
  • 2020-12-23 11:12

    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;
    }
    
    0 讨论(0)
  • 2020-12-23 11:21

    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;
            });
        }
    });
    
    0 讨论(0)
  • 2020-12-23 11:25

    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.

    0 讨论(0)
提交回复
热议问题