bryan
bryan

Reputation: 9389

Checkbox element disappears from serialize() when not checked

I have a form/input checkbox like so:

<form id="the_form">
    <input name="my_checkbox" type="checkbox" value='true' />
</form>

When I run a $("#the_form").serialize(); my_checkbox only comes up as true when it is checked. If it is not checked, there is no data that comes with my_checkbox.

Is there a way I can make it so if the data is not checked, it'll at least give a null value to my_checkbox or something?

Upvotes: 1

Views: 1061

Answers (2)

bryan
bryan

Reputation: 9389

I submit my checkbox through javascript, and since I parse a lot of information in the backend, and my script looks for these variables, it didn't seem like an appropriate solution to do this after the form was submitted.

Thanks to everyone that gave me guidance, but I figured out a way to solve this without too much heavy lifting.

function submitForm()
{
    //serialize all the inputs in the form
    var data_serialize = $("#the_form").serialize();

    //check to see if any checkbox's are not checked, and if so, make them false
    $("#the_form input:checkbox:not(:checked)").each(function(e){ 
          data_serialize += "&"+this.name+'=false';
    });

    //submit the form
    var url = "/submit";
    $.ajax({ type: "POST", url: url, data: data_serialize,
        success: function(data) {  },
        error: function(data) {  }
    });
    return false;
}

Upvotes: 3

ErikE
ErikE

Reputation: 50241

This is normal behavior for HTTP form posts from web browsers: checkbox values are not presented when not checked, since you can infer their value from their absence.

Frankly, this is can be solved with plain engineering: the code that presents the form knows if the checkbox should be present, so the code that receives the post should also know that the checkbox should be present and can implicitly determine the correct, non-checked, value of the checkbox.

If you will give me an indication of your back end technologies I may be able to provide some ideas for how you might engineer the presence of a value for non-checked checkboxes in your form data collection.

If you truly must have the value posted, which I consider less than ideal, then you can add a hidden input that mirrors the value of your checkbox and which is updated by JavaScript:

<form id="the_form">
    <input id="my_checkbox_ui" name="my_checkbox_ui" type="checkbox" value='true' />
    <input id="my_checkbox" name="my_checkbox" type="hidden" value='true' />
</form>
<script>
   $(document).ready(function () {
      $('#my_checkbox_ui').change(function () {
         $('#my_checkbox').val($(this).val());
      });
   });
</script>

Keep in mind that doing this when not absolutely needed creates extra complexity and yields a poorer system:

  • The form post will be larger, using more bandwidth
  • The simple correspondence between visible elements and underlying posted elements is broken, a possible source of confusion and mistakes for future developers working with this code.
  • The need for JavaScript creates additional surface area of possible breakage--there are more moving parts that can break and this causes fragility.
  • Related to the two previous points, if someone copies the form and tries to use it in other code, it won't work correctly, even though the UI looks like it is working.

Another way that you could possibly solve this is to semi-unobtrusively injection the the checkbox-shadowing elements with javascript:

<form id="the_form">
    <input id="my_checkbox_ui" name="my_checkbox_ui" type="checkbox" value='true' />
    <input id="my_checkbox" name="my_checkbox" type="hidden" value='true' />
</form>
<script>
   function getShadowFn(id, shadowId) {
      return function() {
         $('#' + shadowId).val($('#' + id).val());
      };
   }

   function convertCheckboxesToAlwaysPostingCheckboxes() {
      $('input[type="checkbox"]').each(function(id, el) {
         var $el = $(el);
         var name = $el.prop('name');
         var id = $el.prop('id');
         var shadowId = id + '_shadow'
         $el.prop('name', name + '_ui');
         $('<input type="hidden" id="' + shadowId + '" name="' + name + '">')
            .insertAfter($el);
         $el.change(getShadowFn(id, shadowId));
      });
   }

   $(document).ready(convertCheckboxesToAlwaysPostingCheckboxes);
</script>

This is still added complexity, but it is less fragile because it is no longer specific to any checkbox, and all the checkboxes will now work correctly with just this one bit of code (though I didn't test it at all, so please take it as inspiration rather than prescription). So you can get this code working right, and then use it over and over.

Upvotes: 4

Related Questions