22

I have read quite a few different methods of having html checkboxes get posted to the server, but I am really looking to do it without modifying anything except for $.serialize. I ideally, I would like checked boxes to be posted as on, and unchecked to be posted as 0, empty, or null.

I'm a little confused by jquery's inner-workings, but I've got this so far, but it sets unchecked checkboxes to 'on'... Can anyone tell me how to continue this modification below?

$.fn.extend({
    serializeArray: function() {
        return this.map(function(){
            return this.elements ? jQuery.makeArray( this.elements ) : this;
        })
        .filter(function(){
            return this.name && !this.disabled &&
                ( this.checked || !this.checked || rselectTextarea.test( this.nodeName ) || rinput.test( this.type ) );
        })
        .map(function( i, elem ){
            var val = jQuery( this ).val();

            return val == null ?
                null :
                jQuery.isArray( val ) ?
                    jQuery.map( val, function( val, i ){
                        return { name: elem.name, value: val.replace( /\r?\n/g, "\r\n" ) };
                    }) :
                    { name: elem.name, value: val.replace( /\r?\n/g, "\r\n" ) };
        }).get();
    }
});

11 Answers 11

15

This will override the jquery.serialize() method to send both checked/unchecked values, rather than only checked values. It uses true/false, but you can change the "this.checked" to "this.checked ? 'on' : 0" if you prefer.

var originalSerializeArray = $.fn.serializeArray;
$.fn.extend({
    serializeArray: function () {
        var brokenSerialization = originalSerializeArray.apply(this);
        var checkboxValues = $(this).find('input[type=checkbox]').map(function () {
            return { 'name': this.name, 'value': this.checked };
        }).get();
        var checkboxKeys = $.map(checkboxValues, function (element) { return element.name; });
        var withoutCheckboxes = $.grep(brokenSerialization, function (element) {
            return $.inArray(element.name, checkboxKeys) == -1;
        });

        return $.merge(withoutCheckboxes, checkboxValues);
    }
});
2
  • This solution saved me from having to fire an ajax call on every click ... you are my hero. :bow:
    – copremesis
    Commented Apr 12, 2018 at 3:24
  • 1
    Amazing solution, this should be selected as the accepted answer
    – ciosoriog
    Commented Jun 26, 2018 at 2:07
14

just attach the data. In my save routine it's enough to submit unchecked as empty string and checked as "on":

var formData = $('form').serialize();

// include unchecked checkboxes. use filter to only include unchecked boxes.
$.each($('form input[type=checkbox]')
    .filter(function(idx){
        return $(this).prop('checked') === false
    }),
    function(idx, el){
        // attach matched element names to the formData with a chosen value.
        var emptyVal = "";
        formData += '&' + $(el).attr('name') + '=' + emptyVal;
    }
);
1
  • I don't know why, but your solution is adding to serialize even checked checkboxes. So my serialized array has 2 values to same checkbox, one checked and the last one unchecked. Commented Sep 20, 2017 at 14:01
12

I think Robin Maben's solution is missing one step which is to set the boxes to have a property of 'checked'. jQuery's user guide notes on serialise() state that only checked checkboxes are serialised, so we need to add a bit:

$('form').find(':checkbox:not(:checked)').attr('value', '0').prop('checked', true);

The only down-side to this method is a brief flash of your form showing all boxes checked - looks a bit weird.

2
  • Thank you for including "the only down-side" in the answer :)
    – tothemario
    Commented Dec 10, 2016 at 0:44
  • Saved the day! To new guys on Jquery, use this code BEFORE serialize. Commented Sep 20, 2017 at 14:22
3

I like @Robin Maben's approach ( pre-processing the checkboxes before calling the native .serialize() ) but can't make it work without significant modification.

I came up with this plugin, which I have called "mySerialize" (probably needs a better name):

$.fn.mySerialize = function(options) {
    var settings = {
        on: 'on',
        off: 'off'
    };
    if (options) {
        settings = $.extend(settings, options);
    }
    var $container = $(this).eq(0),
        $checkboxes = $container.find("input[type='checkbox']").each(function() {
            $(this).attr('value', this.checked ? settings.on : settings.off).attr('checked', true);
        });
    var s = ($container.serialize());
    $checkboxes.each(function() {
        var $this = $(this);
        $this.attr('checked', $this.val() == settings.on ? true : false);
    });
    return s;
};

Tested in Opera 11.62 and IE9.

As you can see in this DEMO, you can specify the way the checkboxes' ON and OFF states are serialized as an options object passed as a parameter to mySerialize(). By default, the ON state is serialized as 'name=on' and OFF as 'name=off'. All other form elements are serialized as per native jQuery serialize().

2
  • this one won't work then second time, I am not sure where its going wrong, but once you call mySerialize() on the form and then you call mySerialize() again it won't work, it works only the first time. Commented Sep 23, 2015 at 6:33
  • I had to change your answer around slightly for jQuery 1.9 and later. See my answer for the updates. Commented Mar 24, 2017 at 22:05
2
 var x = $('#formname').serializeArray();
 var serialized = $('#formname').find(':checkbox:not(:checked)').map(function () { 
   x.push({ name: this.name, value: this.checked ? this.value : "false" }); 
 });

try this

1
  • These is a good solution as it doesn't change the function which may effect other parts of your site.
    – Goddard
    Commented Sep 10, 2021 at 13:47
1

Beetroot-Beetroot's answer did not work for me in jQuery 1.9 and later. I used .val() and .prop(), and got rid of the .eq(0) requirement on the container, which restricted serializing to one form in the selector. I had a rare case where I had to serialize multiple forms at the same time, so removing that requirement solved that. Here's my modified solution:

$.fn.mySerialize = function(options) {
    // default values to send when checkbox is on or off
    var settings = {
        on: 'on',
        off: 'off'
    };

    // override settings if given
    if (options) {
        settings = $.extend(settings, options);
    }

    // set all checkboxes to checked with the on/off setting value
    // so they get picked up by serialize()
    var $container = $(this),
        $checkboxes = $container.find("input[type='checkbox']").each(function() {
            $(this).val(this.checked ? settings.on : settings.off).prop('checked', true);
        });

    var serialized = ($container.serialize());

    $checkboxes.each(function() {
        var $this = $(this);
        $this.prop('checked', $this.val() == settings.on);
    });

    return serialized;
};

You can see the corresponding fiddle here.

1
  • If $container.find("input[type='checkbox']") not working, please consider to use $container.filter("input[type='checkbox']"), which filter works in all browsers, including IE9+
    – jefferyleo
    Commented Aug 25, 2021 at 14:01
0

I did the following, finding the unchecked checkboxes, checking them before calling serializeArray, then unchecking them so the form would be in the same state as the user left it:

var unchecked = chartCfgForm.find(':checkbox:not(:checked)');
unchecked.each(function() {$(this).prop('checked', true)});
var formValues = chartCfgForm.serializeArray();
unchecked.each(function() {$(this).prop('checked', false)});
0

Here's how I implemented a simple override of $.serializeArray which fixes the default serialization behaviour for checkboxes, and default behaviour is retained for all other types.

In the code below, missed checkboxes are injected into the original serialized array. Checkbox state is returned as "true" (instead of "on") or "false" depending on if it is checked or not.

(function ($) {
    var _base_serializeArray = $.fn.serializeArray;
    $.fn.serializeArray = function () {
        var a = _base_serializeArray.apply(this);
        $.each(this, function (i, e) {
            if (e.type == "checkbox") {
                e.checked 
                ? a[i].value = "true" 
                : a.splice(i, 0, { name: e.name, value: "false" })
            }
        });
        return a;
    };
})(jQuery);

You could customize this to return "on"/"off" or true/false.

0

Another way if you do not have a large forms.

$.fn.serializeForm = function () {
    var form = $(this).clone()
    form.find('input:checkbox:not(:checked)').attr('value', 'off').prop('checked', true);
    return form.serialize();
};

I also like to use better values:

$.fn.serializeForm = function () {
    var form = $(this).clone()
    form.find('input:checkbox:checked').attr('value', 'Yes');
    form.find('input:checkbox:not(:checked)').attr('value', 'No').prop('checked', true);
    return form.serialize();
};

Then

$('#yourForm').serializeForm();
-1

It's a minor change:

    .map(function( i, elem ){
        var val = jQuery( this ).val();
        if ((jQuery(this).checked != undefined) && (!jQuery(this).checked)) {
            val = "false";
        }

I haven't tested but it seems the most logical approach. Good luck

3
  • That worked almost perfectly. I just changed jQuery(this).checked to jQuery(this).prop('checked') and it worked great. Thanks!
    – Jonathon
    Commented Apr 13, 2012 at 19:49
  • @user975571 or simpley use this.checked instead of jQuery(this).prop('checked') Commented Apr 13, 2012 at 19:53
  • for some reason that didn't work, but this finally did: jQuery(this).prop('type') == 'checkbox'
    – Jonathon
    Commented Apr 13, 2012 at 19:54
-1

Before you call serialize(), you need to explicitly set the value to false if a checkbox is unchecked

$(form).find(':checkbox:not(:checked)').attr('value', false);

I have tested it here.

3
  • 1
    This doesn't seem to work for me: the attribute is set all right, but serialize still doesn't show it. Your test page has a number of checkboxes, but no way (that I can see) to test the serialize function to see if it actually works.
    – ibrewster
    Commented Dec 18, 2013 at 21:46
  • @ibrewster: You can wrap them in a form and submit (or $.post) it and check the network tools to see what gets serialized. Commented Apr 3, 2014 at 3:21
  • unchecked checkboxes do not get submitted to the server, regardless of value (hence this question). all checkboxes have a value, since they default to "true" whether or not you set one. stackoverflow.com/questions/11424037/…
    – chiliNUT
    Commented Mar 9, 2015 at 17:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.