How can I serializeArray for unchecked checkboxes? - javascript

How can I modify this example so it can get values from checkboxes that aren't checked?
I want all checkboxes to have a value, if it hasn't been checked I want to get its value as false.
<input type="checkbox" name="Check01" value="true" />
<input type="checkbox" name="Check02" value="true" checked="checked" />
Default behavior
$("form").serializeArray();
// [Check02 = true]
Expected behavior
$("form").serializeArray();
// [Check01 = false, Check02 = true]

It's probably easiest to just do it yourself:
var serialized = $('input:checkbox').map(function() {
return { name: this.name, value: this.checked ? this.value : "false" };
});
If there are other inputs, then you could serialize the form, and then find the unchecked checkboxes with something like the above and append that result to the first array.

serializeArray ignores the checkboxes which are not checked. You can try something like this.
Working demo
var serializedObj = {};
$("form input:checkbox").each(function(){
serializedObj[this.name] = this.checked;
});

you can use this get unchecked values
$.fn.serializeObject = function () {
var o = {};
var a = this.serializeArray();
$.each(a, function () {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
var $radio = $('input[type=radio],input[type=checkbox]',this);
$.each($radio,function(){
if(!o.hasOwnProperty(this.name)){
o[this.name] = '';
}
});
return o;
};
code samples

another option is to just look at the source code for serializeArray and remove (or modify) the call to filter. I Just took that function and created a new one called serializeArrayAll like this:
$.fn.serializeArrayAll = function() {
var rCRLF = /\r?\n/g;
return this.map(function(){
return this.elements ? jQuery.makeArray( this.elements ) : this;
})
/* this is what is excluding the unchecked checkboxes (and also other disabled options)
.filter(function(){
return this.name && !this.disabled &&
( 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( rCRLF, "\r\n" ) };
}) :
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}).get();
};

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.find("input"), 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.
Update: Fixed code based on bug found by #shyammakwana.me.

you can add a hidden false value for every checkbox:
<input type="checkbox" name="Check01" value="true" /><input name="Check01" type="hidden" value="false" />
<input type="checkbox" name="Check02" value="true" checked="checked" /><input name="Check02" type="hidden" value="false" />
You will only get "false" values for unchecked checkboxes and both "true" and "false" for checked checkboxes, so you can remove the duplicates like this:
var params = {};
$.each($('form').serializeArray(), function (index, value) {
params[value.name] = params[value.name] ? params[value.name] || value.value : value.value;
});
console.log(params); // outputs: {"Check01":"false","Check02":"true"}

I made my own new solution based on the answers by #Pointy, #Ben, and the original jQuery code. The answer from #Pointy had odd behavior that returned contexts for checkboxes, this fixes that problem. The answer from #Ben was also not acting properly because it always returned checkbox = on even if it was unchecked.
$.fn.serializeArrayWithCheckboxes = function() {
var rCRLF = /\r?\n/g;
return this.map(function(){
return this.elements ? jQuery.makeArray( this.elements ) : this;
})
.map(function( i, elem ){
var val = jQuery( this ).val();
if (val == null) {
return val == null
//next 2 lines of code look if it is a checkbox and set the value to blank
//if it is unchecked
} else if (this.type == "checkbox" && this.checked == false) {
return { name: this.name, value: this.checked ? this.value : ""}
//next lines are kept from default jQuery implementation and
//default to all checkboxes = on
} else {
return jQuery.isArray( val ) ?
jQuery.map( val, function( val, i ){
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}) :
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}
}).get();
};

Using the jQuery plugin serializeJSON, you can use the data-unchecked-value attribute to specify the value when unchecked:
<input type="checkbox" name="Check01" value="true" data-unchecked-value="false" />
<input type="checkbox" name="Check02" value="true" data-unchecked-value="false" checked="checked" />
JavaScript:
$('input').serializeJSON({ parseBooleans: true });
// returns => { 'Check01' : false, 'Check02' : true }

#SNag's answer worker almost 99% just with little bit correction.
Change below line
from :
$.each(this, function (i, e) {
to:
$.each(this.find('input'), function (i, e) {
Explanation: As this was not working because this returned form element. So on form .each won't give us all input elements inside form. So I did this correction and it worked like charm.

Yet Another SerializeArray()
This implementation is again based on jQuery's original code, but I needed it for some Bootstrap's "switch" checkboxes with two different values.
$.fn.serializeArrayWC = function() {
var rCRLF = /\r?\n/g;
return this.map(function(){
return this.elements ? jQuery.makeArray( this.elements ) : this;
})
.map(function(i, elem){
if (this.type == "checkbox") {
// Bootstrap checkboxes with two different values.
if (jQuery(this).hasClass("switched")) {
// Always return value (either on-value or off-value).
return { name: this.name, value: this.value };
}
// Normal checkboxes. Unchecked checkboxed are not returned.
if (!this.checked) {
// This will be removed by the !!f filter, below.
return false;
}
// Return the value, or "on".
return { name: this.name, value: this.value||"on" };
}
var val = jQuery(this).val();
if (val == null) {
return { name: elem.name, value: null };
} else {
return jQuery.isArray(val) ?
jQuery.map( val, function( val, i ){
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}) :
{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
}
})
.filter(function(i, f){ return !!f; })
.get();
};

You can append unchecked checkbox data to .serializeArray result:
var formData = $("#mybaseelement").serializeArray();
$('#mybaseelement input[type="checkbox"]:not(:checked)').each(function(i, e) {
formData.push({name: e.getAttribute("name"), value: false});
});
This is the least invasive solution I can come up with.

var fields = $("form").serializeArray();
$('form input[type=checkbox]').map(function() {
if( !this.checked )
{
fields.push({ name: this.name, value: "off" });
}
});

Related

Keep checkbox checked or unchecked on page reload, using vanillla JS

I can't wrap my head around this. I have this checkbox:
<input id="copy" name="varcopy" onkeyup="saveValue(this)" tabindex="4"
form="contact_form_id" type="checkbox" value="sendacopy" checked="checked" />
I need to store if the checkbox is checked or unchecked on page reload (whether the checkbox is actived/deactivated by spacebar or on mouseclick). I want to use localStorage for this, in plain JavaScript, no jQuery.
I have these functions to save and restore values of input fields (it works for all text inputs, but not for the checkbox):
function saveValue(e) {
var id = e.id;
var val = e.value;
localStorage.setItem(id, val);
}
function getSavedValue(v) {
if (localStorage.getItem(v) === null) {
return "";
}
return localStorage.getItem(v);
}
I did much research on the net, but I can't find what I specifically need. Please be gentle on me, I'm a beginner. This is what I tried to do with these 2 functions, but it doesn't work at all:
function saveValue(e) {
var id = e.id;
var val = e.value;
if (id == "copy") {
val = e.checked;
}
localStorage.setItem(id, val);
}
function getSavedValue(v) {
if (localStorage.getItem(v) === null) {
return "";
}
if (v == "copy") {
if (localStorage.getItem(v) == true)
return "true";
if (localStorage.getItem(v) == false)
return "false";
}
return localStorage.getItem(v);
}
This is how I invoke the getSavedValue() function:
document.getElementById("copy").value = getSavedValue("copy");
Ok, I'm making progress, this is my checkbox:
<input id="copy" name="varcopy" onkeyup="saveChecked(this)"
onmouseup="saveChecked(this)" tabindex="4"
form="contact_form_id" type="checkbox" />
These are my functions:
function saveChecked(e) {
var id = e.id;
var val = e.checked?1:0;
localStorage.setItem(id, val);
}
function getSavedValue(v) {
if (localStorage.getItem(v) === null) {
return "";
}
return localStorage.getItem(v);
}
And this is the invocation:
document.getElementById("copy").checked = !!getSavedValue("copy");
The problem is it always defaults to true, or always defaults to false. It doesn't switch.
This can be achieved as simple as follows:
var isChecked = !!getSavedValue('someKey');
var checkbox = document.getElementById('copy');
checkbox.checked = isChecked;
!!getSavedValue('someKey'); converts the value returned by your function into a boolean. An empty string, undefined and null will be converted to false and anything else will be converted to true.
Here is modified saveValue function, you can use it.
function saveValue(e) {
var id = e.id;
var val = e.value;
if(e.type === 'checkbox') {
val = e.checked?1:0;
}
localStorage.setItem(id, val);
}
It seems the checked attribute on a checkbox returns either true or false. (Somehow also it is true when unchecked, and false when checked) Problem is that if I do this:
val = e.checked?1:0;
it will always return 1. I think the checked attribute returns a string, not a boolean, so when I do the above in JavaScript, it will always be a non-empty string, meaning it will return true. I had to do this instead:
var val = "";
if (e.checked != true) { //Not-equals because true is unchecked, false is checked
val = "1";
}
Now it works, the checkbox remembers its state on page reload.
The following example will do that for you...
Enjoy... :-)
<script>
function saveData(e) {
let id = e.id;
let val;
if (e.type === 'checkbox'){
val = e.checked;
}else{
val = e.value;
}
localStorage.setItem(id, val);
}
function loadFieldData(id){
let elm = document.getElementById(id);
let value = localStorage.getItem(id);
if (elm) {
if (elm.type === 'checkbox') {
elm.checked = Boolean(value);
}else{
elm.value = value;
}
}
}
function loadData() {
loadFieldData('text1');
loadFieldData('copy');
}
</script>
<body>
<input id="text1" onkeyup="saveData(this)" onchange="saveData(this)" type="text" />
<br/>
<input id="copy" onchange="saveData(this)" type="checkbox" />
<br/>
<br/>
<input type="button" onclick="loadData()" value="Load Data" />
</body>

Knockout - Observable array with subscribe doenst seem to work

Sorry for this lengthy question. I am new to knockout.js.
My business case:
I have a panel with two checkboxes(Yes/No) inside a foreach loop. For some group of items, when one item is selected with 'Yes' checkbox , I need to uncheck 'Yes' checkbox for other items in the group and select the 'No' checkbox for those items.
I am using checked event which is bound to observable array (Yes/No in separate observable arrays).
Items are grouped together by an attribute.(My business case)
One Observable array will hold the 'Yes' selected items.
Another observable array will hold 'No' selected items.
I have a subscribed method to the 'Yes' observable array.
Inside that I have the logic to remove items in the group who already has 'Yes' selected from this observable array.
The subscribe function is called when user 'checks' the checkbox and is also called when the observable array is changed inside the subscribe method due to my logic which I have explained above in Point 6.
Problem: Things seem to work fine which I am able to see through debugging through developer tools, but when the logic to remove the already selected value is executed it is not reflected in the UI. Checkboxes still shows 'Yes' as selected for more than 1 item in the group.
Ex: When One of the item's 'Yes'checkbox is selected in the group the other items 'Yes'checkbox in the group must be unselected. This seems to reflect in the variable values but the UI shows the other items still have 'Yes' checkbox as selected.
My Observable array which holds the 'Yes' selected items still shows the correct values in it(in console) but the UI shows more than 1 item has 'Yes' selected.
Please let me know the issue here.
Html:
<div data-bind="template: { name: 'ItemTemplate', foreach: Items }"></div>
<script type="text/html" id="ItemTemplate">
<!-- Other Html stuffs -->
<div id="SelectionPanel" class="SelectionPanel checkStyle">
<label>
<input type="checkbox" data-bind="value: Id(), click: $root.PersistAutoSelection, checked: $root.SelectedItem, attr: { 'class': SelectStyle, id: 'itemPanelSelected' + $index(), name: 'SelectedIds'}" />
<label data-bind="attr: { 'for': 'PanelSelected' + $index() }">
<p>Yes</p>
</label>
</label>
</div>
<div id="NotRequiredPanel">
<div class="checkbox checkStyle">
<input type="checkbox" class="not-required" data-bind="value: Id(), click: $root.Deselect.bind($data, Id().toString()),checked: $root.NotRequired,attr: { id: 'PanelNotRequired' + $index(), name: 'NotRequiredIds' }" />
<label data-bind="attr: { 'for': 'PanelNotRequired' + $index() }">
<p>No</p>
</label>
</div>
</div>
</script>
Knockout.js script:
var currentlySelectedObject = null;
var isExcessModified = false;
function ViewModel() {
var self = this;
self.SelectedItem = ko.observableArray([]);
self.NotRequired = ko.observableArray([]);
self.Select = function (index) {
self.SelectedItem.push(index.toString());
}
self.Deselect = function (index) {
self.SelectedItem.remove(index.toString());
self.NotRequired.remove(index.toString());
self.NotRequired.push(index.toString());
return true;
}
self.SelectedItem.subscribe(function (newValue) {
var unselectedItem = ko.utils.arrayMap(self.Items(), function (item) {
return item.Id().toString();
});
ko.utils.arrayForEach(self.SelectedItem(), function (itemId) {
ko.utils.arrayRemoveItem(unselectedItem , itemId.toString());
});
if (isExcessModified)
self.ExcessProtectSelectValidation(currentlySelectedObject);
});
self.Remove = function (name) {
ko.utils.arrayForEach(self.Items(), function (item) {
if (item.Name().toLowerCase() == name.toLowerCase()) {
var itemId = item.Id().toString();
self.SelectedItem.remove(itemId);
self.NotRequired.remove(itemId);
}
});
}
self.PersistAutoSelection = function (data, event) {
self.NotRequired.remove(data.Id().toString());
if (!$('#itemPanelSelected' + data.Id().toString()).is(':checked'))
self.SelectedItem.remove(data.Id().toString());
currentlySelectedObject = event.target;
isExcessModified = true;
return true;
}
self.ExcessProtectSelectValidation = function (obj) {
isExcessModified = false;
var yesNoPanel = $(obj).closest('div.bottom');
var schId = $(obj).closest('div.bottom').prev().prev().find("[id^=SchemeID]").val();
if (schId == "AC1" || schId == "AC2" || schId == "AC3") {
//Condition to choose any one of the item
if ($(obj).is(':checked')) {
if (isExcessSelected) {
var itemId = $(obj).closest('[id^="itemPanelInner"]').attr("panelId");
//Logic to remove error message for previous selection
$('*[id*=SchID]').each(function (index) {
if ($(this).val() != schCodeId && ($(this).val() == "AC1" || $(this).val() == "AC2" || $(this).val() == "AC3")) {
Code to show tooltip here;
}
});
//Show error message if try to choose the more than one item had chosen
AddErrorToolTip(yesNoPanel, ToolTipContent);
self.NotRequired.push(itemId.toString());
self.SelectedItem.remove(itemId.toString());
}
else {
//Logic to deselect the other two item, if one the item is already selected
yesNoPanel.removeClass("ErrorHighlight");
yesNoPanel.qtip("destroy", true);
isExcessSelected = true;
if (schId == "AC1" || schId == "AC2" || schId == "AC3") {
$('*[id*=SchID]').each(function (index) {
if ($(this).val() == "AC1" || $(this).val() == "AC2" || $(this).val() == "AC3") {
var itemId = $(this).closest('[id^="itemPanelInner"]').attr("panelId");
if ($(this).val() != schId && ($(this).val() == "AC1" || $(this).val() == "AC2" || $(this).val() == "AC3")) {
var yesNoPanel = $(this).closest('div.top').next().next();
yesNoPanel.removeClass("ErrorHighlight");
yesNoPanel.qtip("destroy", true);
self.NotRequired.push(itemId.toString());
$('#itemPanelSelected' + itemId.toString()).attr('checked', false);
self.SelectedItem.remove(itemId.toString());
}
}
})
}
}
}
else {
isExcessSelected = false;
$('*[id*=SchID]').each(function (index) {
if ($(this).val() == "AC1" || $(this).val() == "AC2" || $(this).val() == "AC3") {
if ($(this).closest("div.top").next().next().find('[id^="ItemPanelNotRequired"]').is(':checked')) {
//Logic to remove the error message if already selected item is unselected
if ($(this).closest('[id^="ItemPanelInner"]').find('div.bottom.ErrorHighlight').length > 0) {
var errorAttachedPanel = $(this).closest('[id^="ItemPanelInner"]').find('div.bottom');
errorAttachedPanel.removeClass("ErrorHighlight");
errorAttachedPanel.qtip("destroy", true);
}
}
}
})
}
}
}
}

jQuery to Pass a Static Value if search is blank

I am passing the search string using $('input[type="text"]').val()
Now the requirement is:
if it is a blank search, then I want to pass Blank Search as the value instead of $('input[type="text"]').val()
AND
if it not blank and having a value, I want to pass the same value using $('input[type="text"]').val().
What I have tried:
$(document).on('click','.fa.fa-search', function()
{
ga('create', {{ GA Property }}, 'auto');
ga('send', 'event', 'Search',
function blank ()
{
alert('hi');
var srchStr = $('input[type="text"]').val();
if(srchStr == '') { srchStr = "Blank Search"; }
},
window.location.href);
});
How to do it?
Try this:
var srchStr = $('input[type="text"]').val();
if(srchStr == '')
{
srchStr = "Blank Search";
}
Working Fiddle
html:
<input type="text" />
<input type="button" val="test">
jquery :
$('input[type="button"]').on("click", function() {
var val = $('input[type="text"]').val().trim().length > 0 ? $('input[type="text"]').val() : "Your Default value"
alert(val);
});
Simplest way:
if($('input[type="text"]').val() == '')
{
$('input[type="text"]').val("Blank Search");
}
Try this:
var input = $('input[type="text"]');
var srchStr = input.val();
if(srchStr != '' && srchStr.trim().length > 0){
input.val(srchStr);
}else{
input.val("Blank Search");
}
See this example with avoiding extra spaces.
var v = $('input[type="text"]').val().replace(/\s+/,"");
v = v === "" ? "Blank Search" : $('input[type="text"]').val();

JavaScript Model Form Validation

I am using BackboneJS MVC pattern and have a form with 2 fields which the user can select.
I call changeAction whenever there is any change in selection by the user (to call validation);
changeAction: function (event) {
var self = this;
var target = event.target;
target.value = $.trim(target.value);
change[target.name] = target.value;
this.model.set(change);
var check = self.model.validateItem(target.id);
if (check.isValid === false) {
self.addValidationError(target.id, check.message);
} else {
self.removeValidationError(target.id);
}
}
My validation is defined in the Model as below;
this.validators.myDropDownField = function(value) {
return !_.isUndefined(value) && !_.isNull(value) && $.trim(value).length > 0 ? {
isValid: true
} : {
isValid: false,
message: "Select dropdown field"
};
};
validateItem: function(key) {
var result = (this.validators[key]) ? this.validators[key](this.get(key)) : {
isValid: true
};
return result;
}
Now my question is I do not want to do anything to the Model in changeAction.
But if I remove the line this.model.set(change) in changeAction()
the validation does not work correctly. I do not get the value in the function
this.validators.myDropDownField
How do I handle this ?

foreach object/array in jQuery

I have a problem, i have X <input type="checkbox" /> in my code, now I want to foreach this object/array its out put. - look my code.
$("#denied_seekrs").click(function()
{
if (!isCheckedById("selectname"))
{
alert ("Please select at least one event");
return false;
}
else
{
alert( $("input[#id=selectname]:checked").val() ); //submit the form
}
});
function isCheckedById(id)
{
var checked = $("input[#id="+id+"]:checked").length;
if (checked == 0)
{
return false;
}
else
{
return true;
}
}
When I output it in alert i get a object, but if I have select 2 checkbox I what the value in this 2 checkboxes.
I hope I can be helpful and all here understand me :)
How about
$("#denied_seekrs").click(function() {
var checkedInputs = $("input:checked");
var test = "";
$.each(checkedInputs, function(i, val) {
test += val.value+",";
});
test = test.substring(0,(test.length-1));
alert(test);
});
I'm not exactly sure what you're looking for, but I'm guessing that the jQuery.each() method will help. You can use it to iterate over arrays, objects, and more.
var arr = [ "one", "two", "three", "four", "five" ];
jQuery.each(arr, function() {
$("#" + this).text("My id is " + this + ".");
return (this != "four"); // will stop running to skip "five"
});
how about something like this:
jQuery.each(checked, function() {
$(checked + this).text("My id is " + this + ".");
});
Can it be that - ultimately - you are looking for $.serializeArray() or $.serialize()?
If not, then maybe this is helps you:
$("#denied_seekrs").click(function()
{
if (!isCheckedById("selectname"))
{
alert ("Please select at least one event");
return false;
}
else
{
// prepare array of values
var values = [];
// prepare list of checked checkboxes
var $checkboxes = $("input[#id=selectname]:checked");
// push each individual value into the array
$checkboxes.each(function() { values.push( $(this).val() ); });
// debug output
alert( values.join("\n") );
//submit the form
}
});
When I got you right, you want the user to select one checkbox (or is it one or more?). This should do it:
$("#denied_seekrs").click(function()
{
var $checkedInputs = $("input:checked");
if ($checkedInputs.length != 1)
{
alert ("Please select one event");
return false;
}
alert( $checkedInputs.val() ); //submit the form
});
EDIT:
After reading your question again, I realized that the above code does not answer your question. However, the above does work and is a much shorter version of your solution. Maybe you want to use it instead. To answer your question, you could alert the value of all checked boxes like this:
Change this:
alert( $checkedInputs.val() ); //submit the form
to this:
var values = "";
$checkedInputs.each(function(){
values += $(this).val() + " ";
});
alert( values );

Categories