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

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
check the checkbox
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());
}
);

Related

JavaScript - Toggle "check all" checkboxes true/false

I am trying to make "toggle checkboxes" function, as below:
HTML Code:
<!-- "Check all" box -->
<input type="checkbox" name="check" id="cbx_00_00" onclick="selectbox( this.getAttribute( 'id' ));" />
<!-- the other ones -->
<input type="checkbox" name="check" id="cbx_00_01" />
<input type="checkbox" name="check" id="cbx_00_02" />
<input type="checkbox" name="check" id="cbx_00_03" />
JavaScript:
function selectbox( eID ) {
// instead of writing the element id in the html code,
// i want to use "this.getAttribute( 'id' )"
var c = document.getElementById( eID );
// now when we've got the id of the element,
// let's get the required attribute.
var box = c.getAttribute( 'name' );
// set var i value to 0, in order to run "for i" loop
var i = 0;
for(i; i < box.length; i++) {
// now lets find if the main box (as box[0]) checked.
// if returns true (it has been checked), then check all - else -
// do not check 'em all.
if(box[0].checked == true) {
box[i].checked = true;
}
else {
box[i].checked = false;
}
}
}
I don't want any jQuery solution (even if it can be easier than pure js), so please avoid suggesting it. All I want to know is - If I'm wrong - what do you think I should do to solve this?
Thank you very much. every suggestion/tip is appreciated.
Your problem mainly seems to be that you are iterating over the checkbox name, not the checkboxes with that name.
var box = c.getAttribute( 'name' );
Now, box is equal to "check", so box[0] is "c", box[1] is "h" etc.
You need to add this:
var boxes = document.getElementsByName(box);
And then iterate over boxes.
Of course, at that point, you may want to rename your variables too.
Given the name in the variable box, you can check all boxes with the same name like this:
Array.prototype.forEach.call(document.getElementsByName(box), function(el) {
el.checked = true;
});
(Array.prototype.forEach.call is used to loop over the "fake-array" returned by getElementsByName because the NodeList class doesn't have forEach.)
I think you can further simply your code by not passing the element's ID to your function, but directly the name (selectbox(this.name)). Also note that you can access ID and name using .id and .name instead of using getAttribute.
You can make it simple.
HTML Code:
input type="checkbox" name="check" id="cbx_00_00" onclick="selectbox(this.getAttribute('name'));" />
<input type="checkbox" name="check" id="cbx_00_01" />
<input type="checkbox" name="check" id="cbx_00_02" />
<input type="checkbox" name="check" id="cbx_00_03" />
Javascript:
function selectbox(eID) {
var checkBoxes = document.getElementsByName(eID);
for (var i = 0; i < checkBoxes .length; i++) {
if (checkBoxes[0].checked) {
checkBoxes[i].checked = true;
}
else {
checkBoxes[i].checked = false;
}
}
}

Log all items of checked checkboxes to console

I have three checkboxes which have a class name of (names). I am trying to say if the checkbox is checked log the value to the console.
if( $('.names').is(':checked') ){
console.log($('.names').val());
}else{
console.log('null');
}
However, this is only logging the first value to the console (when there is more than one ticked).
Do i need to create an array and log that?
The getter version of val() will return the value of the first element only.
One solution is to get an array of all the checked values and print it
var checked = $('.names:checked').map(function() {
return this.value;
}).get();
if (checked.length) {
console.log(checked);
} else {
console.log('null');
}
While you have a correct answer posted already, it's worth noting that jQuery is not required for this to be 'easy'; it's quite possible in vanilla JavaScript:
// creating a named function to handle the change-event (later):
function logToConsole() {
// retrieves a collection of elements that match the CSS selector:
var checked = document.querySelectorAll('input[type=checkbox].names:checked'),
// converts the collection to an Array:
values = Array.prototype.slice.call(checked, 0)
// map iterates over the Array returned by
// Array.prototype.slice():
.map(function(checkbox) {
// checkbox is the Array Element itself:
// returning the value of the checked checkbox:
return checkbox.value;
});
// if the collection has a length other than 0:
if (checked.length) {
// outputs the array of values to the console:
console.log(values);
}
}
document.querySelector('form').addEventListener('change', logToConsole);
<form action="#" method="post">
<fieldset>
<legend>Check any of the check-boxes to see the values of those check-boxes logged to the console</legend>
<label>value: 3
<input value="3" class="names" type="checkbox" />
</label>
<label>value: 4
<input value="4" class="names" type="checkbox" />
</label>
<label>value: 5
<input value="5" class="names" type="checkbox" />
</label>
<label>value: 6
<input value="6" class="names" type="checkbox" />
</label>
</fieldset>
</form>
Vanilla Javascript solution:
[].forEach.call(document.querySelectorAll('.names:checked'), function (cb) {
console.log(cb.value);
});
And if you wan't that for older browsers as well:
var cbs = document.querySelectorAll('.names:checked');
for(var i = 0; i < cbs.length; i++)
console.log(cbs[i].value);

Adding an array value to an array retrieved using $.serializeArray()

There are checkboxes, which belong to Form A:
<input type="checkbox" class="item-selector" name="item[]" value="1" />
<input type="checkbox" class="item-selector" name="item[]" value="2" />
<input type="checkbox" class="item-selector" name="item[]" value="3" />
<!-- etc. -->
Then I have Form B that needs the checkbox values from Form A. Form A might have other input fields too, but I'm not interested in those. I only care about $('input.item-selector'). I'm going about it like this:
var postData = $('#form-a').serializeArray();
var items = $('.item-selector:checked').map(function(){
return this.value;
}).get();
if(items.length > 0) {
postData.push({name: 'itemId', value: items});
}
But this way of adding stuff to the postData doesn't seem to work, because the PHP script I send the form to can not find the itemId. Interestingly this does work:
postData.push(name: 'aName', value: 'notAnArrayButAStringValue');
I also tried a couple of solutions like this one: http://benalman.com/projects/jquery-misc-plugins/#serializeobject but the problem with them is that, while they otherwise work fine, for some reason if there are checkboxes in Form B, the checkbox values of Form B are parsed incorrectly and result in null values and loss of data. That would look like this:
var postData = $(this.form).serializeObject();
var items = $('.item-selector:checked').map(function(){
return this.value;
}).get();
if(items.length > 0) {
postData.itemId = items;
}
Using JSON.stringify revealed the object structure to be like this:
{
"name":"Simon J. Kok",
"address_id":"39669",
"email":"*****",
"content_id":"21921",
"client_id":"42101",
"is_ebill":["","1"], <-- this is a checked checkbox
"is_banned":"", <-- this is an unchecked checkbox
"button":"save"
}
The checkboxes in Form B look like
<input type="checkbox" value="1" name="is_ebill" />
<input type="checkbox" value="1" name="is_banned" />
So what I need is either some insight on how to add the checkboxes from Form A to the $.serializeArray() result array -OR- a way to solve the issue of a checked checkbox returning an array when using Ben Alman's plugin.
Here's one approach. First it requires a hidden field in form-b:
<input type="hidden" id="itemId" name="itemId" value="" />
This would be populated with the item-selector data when the form is submitted:
$('#form-b').on('submit', function() {
var checkedValues = [];
$('.item-selector:checked').each(function() {
checkedValues.push($(this).val());
});
$('#itemId').val(checkedValues.join(','));
console.debug('Form B data:', $('#form-b').serializeArray());
});
Adjust the syntax to suit your idiom. Here's a fiddle to demonstrate:
http://jsfiddle.net/klenwell/12evxfvc/
Actually I kinda answered my own question already when I asked it. I used JSON.Stringify to output the JSON formatted string of what $.serializeArray() returned and it became apparent what the structrure needed to work. So here is how to add array values one by one to an array retrieved using $.serializeArray():
var items = $('.item-selector:checked').map(function(){
return this.value;
}).get();
$.each(items, function(i, v){
postData.push({name: 'itemId[]', value: v});
});

how to call a javascript function on radio button's 'checked' property?

I have N number of radio button groups in the page with auto generated names.
I want to call a javascript function as the value of the checked property. THIS LINE EXCLUDED AFTER EDIT ( Depending on the return value, the radio button needs to be checked or unchecked.)
<input type="radio" name="auto_generated_name" value="some_value" checked="test_check(args);" />
and the javascript function is
function test_check(params) {
if(conditions){
return true;
}
else
return false;
}
But that does not work. Whatever value I assign to 'checked' property, be it any javascript function or any string etc, the radio button becomes checked.
How can I achieve my goal?
EDIT:
<input type="radio" name="auto_generated_name" value="somevalue" onclick="test_check(args)"/>
4 radio buttons make a group. such N radio groups have html class names in this way : button_group_1, button_group_2, button_group_3, button_group_4 etc.
The 'args' need to be these class (i.e. radio button group) names and the corresponding values (from value="1", value="2", value="3" and value="4" ).
Cookies with the class names and values will be created inside the javascript function.
On page refresh, cookies matching with the class names will be checked and depending on the existence of the corresponding cookies, the radio button will be checked or unchecked.
How to achieve the goals/
Assuming you are using jQuery, use the change event: http://api.jquery.com/change/
The checked attribute is simply a boolean value to indicate whether the radio button should be checked, it cannot contain script, or a reference to a scripting function. Any value in the attribute will cause the radio button to be checked.
Without knowing what mechanism you are using to check each radio button - I can see an args variable but don't know what type this is - it's going to be tricky to write some code for you.
If you can make args into an array of values, then something along the lines of the following should work for you:
var args = new Array(true,false,true)
$.each(args, function(index, value) {
$("INPUT[type=radio]").eq(index).attr("checked", value)
});
Here's a fiddle to show what I mean more clearly
check this output, valid args is 'aa'.
http://jsfiddle.net/X7rcC/1
html:
<input type="radio" name="auto_generated_name" value="some_value1" checked="bb" />
js:
$(function() {
var radios = $("input[type='radio']");
$.each(radios, function(index, value){
var args = value.attributes[1].nodeValue;
test_check(args, value);
})
});
function test_check(params, value){
if(params == "aa"){
$(value).attr("checked",true);
}else
$(value).attr("checked",false);
}
try this:
Here I user a custom attribute to input named groupname. In OP's case groupname="<?php echo $radio_button_group_name; ?>". Then checking the value of this attribute OP can assign checked attribute value.
<input type="radio" name="r1" groupname="gr1"/>
<input type="radio" name="r2" groupname="gr2"/>
$('input:radio').each(function() {
if ($(this).attr('groupname') == 'gr1') {
$(this).attr('checked', true);
} else {
$(this).attr('checked', false);
}
});
Your question really boils down to:
How can I set the value of a checkbox when the page first loads? (Using a parameter stored with the checkbox)
The key insights are:
you can't store a function inside a parameter and expect it to automatically evaluate on load
you can store the data about an object inside data- properties
you can set the value of objects on page load in jQuery using the $(document).ready() event
.
<script type="text/javascript">
$(document).ready( function() { // this code runs when the page is first loaded
var radios = $("input[type='radio']"); // find all of your radio buttons
$.each(radios, function(){
var radio = $(this);
var param = radio.attr('data-param'); // retrieve the param from the object
radio.attr('checked', test_check(param) ); // set the value of the radio button
})
});
function test_check(params) {
if(conditions){
return 'checked';
}
else
return '';
}
</script>
You cannot use a checked attribute this way, because anything as the value will be the same as checked=true Even just checked checks a radio button. What you should do is use a custom attribute which will create the checked attribute:
<input type="radio" name="auto_generated_name" value="some_value" needs_check="param">
<script>
// Do test_check on param for each input
$('input:radio').each(function()
{
var radio = $(this);
var param = radio.attr('needs_check');
var condition = test_check(param);
radio.attr('checked', condition);
});
function test_check(param)
{
return true or false based on param
}
</script>
I was facing same problem and my conclusion is that don't use " " to contain a function.
Correct:
<input type="radio" name="im" id="b1" onclick=alert("hello"); />
Incorrect:
<input type="radio" name="im" id="b1" onclick="alert("hello");" />

Better method of retrieving values of checked input boxes via jQuery?

I have several checkboxes and a fake submit button to make an AJAX request:
<form>
<input type="checkbox" value="1"/>
<input type="checkbox" value="2" checked="checked"/>
<input type="checkbox" value="3"/>
<input type="checkbox" value="4" checked="checked"/>
<input type="button" onclick="return mmSubmit();"/>
</form>
Within the mmSubmit() method, I would like to retrieve an array of values that have been selected. Here is what I am currently doing.
mmSubmit = function() {
var ids = [];
$('input[type=checkbox]:checked');.each(function(index) {
ids.push($(this).attr('value'));
});
// ids now equals [ 2 , 4 ] based upon the checkbox values in the HTML above
return false;
};
I'm wondering if there is a shorthand method in jQuery used to retrieve the values into an array, or if what I have is already optimal.
I think this can be accomplished with map. Try the following..
mmSubmit = function() {
var ids = $('input[type=checkbox]:checked').map(function(){
return $(this).val();
}).get();
// ids now equals [ 2 , 4 ] based upon the checkbox values in the HTML above
return false;
};
Take a look at: jQuery Traversing/Map
Well you can use .val() instead of .attr('value').
$.serializeArray() may also do what you want (http://docs.jquery.com/Ajax/serializeArray).
It's needs some optimization, buts generally it is right way. My variant:
mmSubmit = function () {
var ids = [];
$('input[type=checkbox]').each(function () {
if (this.checked) {
ids[ids.length] = this.value;
}
});
return ids;
};
It's little faster.

Categories