简体   繁体   中英

jQuery - serializeArray() is not getting the value of the checked checkbox

I have a checkbox in a form that acts as a flag.

In order to do it, I added a hidden input element so that if the checkbox is not checked, something will still be saved

<form action="">
    ...
        <input type="hidden" name="foo" value="no" />
        <input type="checkbox" name="foo" value="yes">
    ...
</form>

The problem I am having is that when I

  1. check the checkbox
  2. then run jQuery.serializeArray() on the form

the value set for the foo element is "no"

Object { name="foo", value="no"}

Shouldn't serializeArray() emulate browser behaviour? If so, shouldn't it return "yes" if checkbox is checked?

I am using jQuery v1.10.2

In a short word: No. The serializeArray method only returns the checkbox in the case it is checked. Thus, it will ignore it as long as it remains unchecked. In case you checked it, though, it wiill return the value of your input directly.

Check out the demo at http://api.jquery.com/serializearray/ .

Using serializeArray on a form with multiple inputs of the same name returns more than one object for each element (if checked). This means that the following HTML will return the following object. So the data in question is there and is available. Because of this I'm assuming that you're attempting to either manipulate the data to be in 1 object or you're posting it to a server which is only taking into account the data from the first value with that key. You just need to make sure that any checkbox element takes precedence.

Returned Object:

[
    {
        name:"foo",
        value:"no"
    },
    {
        name:"foo2",
        value:"no"
    },
    {
        name:"foo2",
        value:"yes"
    }
] 

HTML:

<form>
    <input type="hidden" name="foo" value="no" />
    <input type="checkbox" name="foo" value="yes" />

    <input type="hidden" name="foo2" value="no" />
    <input type="checkbox" name="foo2" value="yes" checked />
</form>

JS:

console.log($('form').serializeArray());

DEMO

Another way you can do this is get rid of the hidden fields and before you submit the form go through each unchecked checkbox and check if there is any data in the serializeArray with the same name. If not just add it in there as a off .

$('#submit').on('click', function(){
    var arr = $('form').serializeArray(),
        names = (function(){
            var n = [],
                l = arr.length - 1;
            for(; l>=0; l--){
                n.push(arr[l].name);
            }

            return n;
        })();

    $('input[type="checkbox"]:not(:checked)').each(function(){
        if($.inArray(this.name, names) === -1){
            arr.push({name: this.name, value: 'off'});
        }
    });

    console.log(arr);
});

DEMO

Using the same name for multiple fields is problematic at best and there is no standardized way that front end systems, or back end systems, will handle it.

The only reason to use the same name is if you are trying to pass some kind of a default value, like you are in the case below, where you are doing a simple yes/no.

What you want, to emulate the browser, is serialize method, not the serializeArray .

I added the form to a page -- from my console:

JSON.stringify(f.serializeArray());
"[{"name":"foo","value":"no"}]"

NO checkmark

JSON.stringify(f.serialize());
""foo=no""

Checkmark

JSON.stringify(f.serialize());
""foo=yes&foo=no""

If your back end system gets confused and is picking up the wrong value, reverse the order of your checkmark and hidden element.

FACT : jQuery serializeArray() does not include unchecked checkboxes that probably we DO need them sent to server (no problem for radios though).

SOLUTION : create a new serialize :

//1. `sel` any collection of `form` and/or `input`, `select`, `textarea` 
//2. we assign value `1` if not exists to radios and checkboxes
// so that the server will receive `1` instead of `on` when checked
//3. we assign empty value to unchecked checkboxes 
function serialize(sel) {
   var arr,
       tmp,
       i,
       $nodes = $(sel);

   // 1. collect form controls
   $nodes = $nodes.map(function(ndx){
      var $n = $(this);

      if($n.is('form'))
         return $n.find('input, select, textarea').get();
      return this;
    });

   // 2. replace empty values of <input>s of type=["checkbox"|"radio"] with 1 
   // or, we end up with "on" when checked
   $nodes.each(function(ndx, el){
      if ((el.nodeName.toUpperCase() == 'INPUT') && ((el.type.toUpperCase() == 'CHECKBOX') || (el.type.toUpperCase() == 'RADIO'))){
         if((el.value === undefined) || (el.value == ''))
            el.value = 1;
      }
   });

   // 3. produce array of objects: {name: "field attribute name", value: "actual field value"}
   arr = $nodes.serializeArray();
   tmp = [];
   for(i = 0; i < arr.length; i++)
      tmp.push(arr[i].name);

   // 4. include unchecked checkboxes
    $nodes.filter('input[type="checkbox"]:not(:checked)').each(function(){
      if(tmp.indexOf(this.name) < 0){
         arr.push({name: this.name, value: ''});
      }
    });

   return arr;
}

The reason we assigned empty string to unchecked checkboxes is because a checked one will submit it's value to server which is set in html and can be a zero!!!

So, an empty value denotes a unchecked checkbox.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

<form url="http://application.localdev/api/v1/register" method="post" id="formReg" accept-charset="utf-8">
    <input type="email" placeholder="email" name="email"><br>
    <input type="text" placeholder="firstname" name="firstname"><br>
    <input type="text" placeholder="lastname" name="lastname"><br>
    <input type="number" placeholder="zip_code" name="zip_code"><br>
    <input type="checkbox" name="general" value="true"> general<br>
    <input type="checkbox" name="marketing" value="true"> marketing<br>
    <input type="checkbox" name="survey" value="true"> survey<br>
    <button type="submit">save</button>
</form>

<script>
    $(document).ready(function() {
        $('#formReg').on('submit', function(e){
            // validation code here
                        
            e.preventDefault();


                            
            var values = {};
            $.each($('#formReg').serializeArray(), function(i, field) {
                values[field.name] = field.value;
            });

            $('input[type="checkbox"]:not(:checked)').each(function(){
                if($.inArray(this.name, values) === -1){
                    values[this.name] = $(this).prop('checked')
                }
            });

            console.log(values)
        });
    });
</script>

serializeArray doesn't return unchecked checkbox. I try this instead of serializeArray :

$('input, select, textarea').each(
   function(index){  
       var input = $(this);
       alert('Type: ' + input.attr('type') + 'Name: ' + input.attr('name') + 
       'Value: ' + input.val());
   }
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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