POST unchecked checkboxes with values to Node [duplicate] - javascript

I have an HTML form with an array of checkboxes (using [] naming). I need to be able to process this with express. I'm using body-parser.
The problem is that unchecked checkboxes don't submit a value, and at the same time, body-parser seems to remove "holes" in arrays by simply packing the values into an array in order of indices, but ignoring the indices themselves. (Update: Actually it looks like qs is the culprit).
Consider this full example, which displays a form and responds with a JSON dump of the submitted data:
Install:
npm install express body-parser
index.js:
var express = require("express");
var site = express();
site.use(require("body-parser").urlencoded({extended:true}));
site.get("/", function (req, res) {
res.sendFile(__dirname + "/test.html");
});
site.post("/form", function (req, res) {
res.json(req.body);
});
site.listen(8081);
test.html:
<html>
<body>
<form method="post" action="/form">
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1"><br>
<input type="text" name="text[0]"><br>
<input type="text" name="text[1]"><br>
<input type="text" name="text[2]"><br>
<button type="submit">Submit</button>
</form>
</body>
</html>
In that example, if I were to check only option[1], I verify that the index is set correctly by inspecting the request in Chrome, body is:
option[1]:1
text[0]:
text[1]:
text[2]:
Yet body-parser collapses the option array and produces the following in req.body:
{"option":["1"],"text":["","",""]}
As you can see, text has all three, but option has only one item. Similarly, if I were to check option[0] and option[2], the request body would look like:
option[0]:1
option[2]:1
text[0]:
text[1]:
text[2]:
But it would be parsed to:
{"option":["1","1"],"text":["","",""]}
I lose all information about which checkbox was checked.
My question is, how do I do this? What I want to happen is, e.g.:
With checkbox[1] checked:
{"option":[null,"1",null],"text":["","",""]}
With checkbox[0] and checkbox[2] checked:
{"option":["1",null,"1"],"text":["","",""]}
I'm not actually married to null and "1", I just need falsey and truthy.
Also, it is important that I not lose information about how many checkboxes should be in the array. For example, if I were to give each checkbox a unique value, I suppose I could translate "option":["0","1"] into an array of boolean values, except I would lose the knowledge that the array is of size 3 (with the 3rd value false in that case) -- although I guess I could add e.g. a hidden input like numberOfCheckboxes=3, but... this kind of mapping is cumbersome and I'd like to avoid it if possible.

My approach requires no javascript on client side.
Add hidden fields as many as your checkboxes with same names
body parser will parse checked items as array and string others
I meant
<input type="hidden" name="option[0]" value="0">
<input type="hidden" name="option[1]" value="0">
<input type="hidden" name="option[2]" value="0">
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1">
If your option[1] is checked then body parser will parse it like
{option:['0', ['0', '1'], '0']}
And here is the modifier
req.body.option = req.body.option.map(item => (Array.isArray(item) && item[1]) || null);
so now body will be
{option: [null, '1', null]}

The simplest solution (not the best) is that you can add hidden input's with different ids and then check them when the check-boxes on the page get unchecked.
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1">
<input type="checkbox" class="hidden" name="hiddenOption[0]" value="1">
<input type="checkbox" class="hidden" name="hiddenOption[1]" value="1">
<input type="checkbox" class="hidden" name="hiddenOption[2]" value="1">
And before submit:
$('input[name^=option]').each(function () {
if(!this.checked) {
var name = "input[name=\'hiddenOption" + this.name.replace('option', '') + "\']";
console.log(name);
$(name).prop('checked', true);
}
});
And then based on that you can figure out which ones are not ticked.
https://plnkr.co/edit/mJCbtgQnQudHGrUzAz3A?p=preview

Related

Get Values of Selected Checkboxes in Express Data API?

So I have multiple input checkboxes, but I want to only get the data if I select the checkbox for my express post function
So here is 3 checkboxes I have with different values of 1000,2000, & 3000
<input type="checkbox" name="item1" value="1000" class="food">
<input type="checkbox" name="item2" value="2000" class="food">
<input type="checkbox" name="item3" value="3000" class="food">
Now in express post function when I submit my form, I can get my data like this
const response = await client
{
other_data: 'other data from my forms'
total_cost: parseInt(req.body.item1) + parseInt(req.body.item2) + parseInt(req.body.item3),
}
The problem is when I submit my form, it will only calculate the total if I select all 3 input checkboxes and hence display the total_cost of 6000
But if I only click on one input checkbox, then submit my form it will show the value of 0 even though I clicked one input 1 with a value of 1000.
How do I add my data in express so that it will display my input checkbox value based on the input I clicked on? Because if I had 100 inputs, then manually adding them seems inefficient
Just use the OR operator to catch any missing values and set them to zero:
total_cost: parseInt(req.body.item1||'0') + parseInt(req.body.item2||'0') + parseInt(req.body.item3||'0'),
To better manage the input data on the backend, give each checkbox the same name attribute.
<input type="checkbox" name="items" value="1000" class="food">
<input type="checkbox" name="items" value="2000" class="food">
<input type="checkbox" name="items" value="3000" class="food">
Then on the backend, you can just add up the values as such:
total_cost: req.body.items?.reduce((a,b) => a+(+b), 0) || 0,

Unchecked input checkbox with identical ids

I'm trying to get the values of an input of type checkbox with the same ID, and try to get the click (the checked), to the one with the value 1
but when I do the console.log I only get the value of the first input and it does not get both values.
i.e. to bring me the value number 2 of the first one and not 2 and 1.
<script>
var s = document.getElementById("switchA").value;
console.log(s);
</script>
These inputs are of checkbox type so if one of them has value two it should be unchecked.
<input type="checkbox" name="asd" id="switchA" value="2">
<input type="checkbox" name="asdf" id="switchA" value="1">
You shouldn't be giving the same id to multiple elements on a page. However, assuming you are not able to change the HTML, you can use the following to select multiple elements with the same id:
var s = document.querySelectorAll("[id='switchA']");
You should use a name or class instead to group the checkboxes. Ids are meant to be unique in a document.
const vals = [...document.querySelectorAll('input[type=checkbox][name=someName]')]
.map(x => x.value);
console.log(vals);
<input type="checkbox" name="someName" value="2">
<input type="checkbox" name="someName" value="1">
However, you could use an attribute selector to obtain all elements with a specific id, but that is not recommended.
const vals = [...document.querySelectorAll("[id=switchA]")]
.map(x => x.value);
console.log(vals);
<input type="checkbox" name="asd" id="switchA" value="2">
<input type="checkbox" name="asdf" id="switchA" value="1">

Express body-parser handling checkbox arrays on forms

I have an HTML form with an array of checkboxes (using [] naming). I need to be able to process this with express. I'm using body-parser.
The problem is that unchecked checkboxes don't submit a value, and at the same time, body-parser seems to remove "holes" in arrays by simply packing the values into an array in order of indices, but ignoring the indices themselves. (Update: Actually it looks like qs is the culprit).
Consider this full example, which displays a form and responds with a JSON dump of the submitted data:
Install:
npm install express body-parser
index.js:
var express = require("express");
var site = express();
site.use(require("body-parser").urlencoded({extended:true}));
site.get("/", function (req, res) {
res.sendFile(__dirname + "/test.html");
});
site.post("/form", function (req, res) {
res.json(req.body);
});
site.listen(8081);
test.html:
<html>
<body>
<form method="post" action="/form">
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1"><br>
<input type="text" name="text[0]"><br>
<input type="text" name="text[1]"><br>
<input type="text" name="text[2]"><br>
<button type="submit">Submit</button>
</form>
</body>
</html>
In that example, if I were to check only option[1], I verify that the index is set correctly by inspecting the request in Chrome, body is:
option[1]:1
text[0]:
text[1]:
text[2]:
Yet body-parser collapses the option array and produces the following in req.body:
{"option":["1"],"text":["","",""]}
As you can see, text has all three, but option has only one item. Similarly, if I were to check option[0] and option[2], the request body would look like:
option[0]:1
option[2]:1
text[0]:
text[1]:
text[2]:
But it would be parsed to:
{"option":["1","1"],"text":["","",""]}
I lose all information about which checkbox was checked.
My question is, how do I do this? What I want to happen is, e.g.:
With checkbox[1] checked:
{"option":[null,"1",null],"text":["","",""]}
With checkbox[0] and checkbox[2] checked:
{"option":["1",null,"1"],"text":["","",""]}
I'm not actually married to null and "1", I just need falsey and truthy.
Also, it is important that I not lose information about how many checkboxes should be in the array. For example, if I were to give each checkbox a unique value, I suppose I could translate "option":["0","1"] into an array of boolean values, except I would lose the knowledge that the array is of size 3 (with the 3rd value false in that case) -- although I guess I could add e.g. a hidden input like numberOfCheckboxes=3, but... this kind of mapping is cumbersome and I'd like to avoid it if possible.
My approach requires no javascript on client side.
Add hidden fields as many as your checkboxes with same names
body parser will parse checked items as array and string others
I meant
<input type="hidden" name="option[0]" value="0">
<input type="hidden" name="option[1]" value="0">
<input type="hidden" name="option[2]" value="0">
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1">
If your option[1] is checked then body parser will parse it like
{option:['0', ['0', '1'], '0']}
And here is the modifier
req.body.option = req.body.option.map(item => (Array.isArray(item) && item[1]) || null);
so now body will be
{option: [null, '1', null]}
The simplest solution (not the best) is that you can add hidden input's with different ids and then check them when the check-boxes on the page get unchecked.
<input type="checkbox" name="option[0]" value="1">
<input type="checkbox" name="option[1]" value="1">
<input type="checkbox" name="option[2]" value="1">
<input type="checkbox" class="hidden" name="hiddenOption[0]" value="1">
<input type="checkbox" class="hidden" name="hiddenOption[1]" value="1">
<input type="checkbox" class="hidden" name="hiddenOption[2]" value="1">
And before submit:
$('input[name^=option]').each(function () {
if(!this.checked) {
var name = "input[name=\'hiddenOption" + this.name.replace('option', '') + "\']";
console.log(name);
$(name).prop('checked', true);
}
});
And then based on that you can figure out which ones are not ticked.
https://plnkr.co/edit/mJCbtgQnQudHGrUzAz3A?p=preview

Javascript checkbox validation: how to alert if user didn't check a particular checkbox?

So what I am doing is something like a simple medication reminder, so the system display a list of medications the user should be taking, and the user then tick the checkbox of the medicine they have taken, but what I want to do is if for example, the user only ticked Medicine One and Two, then I want an alert saying "Why you didn't take Medicine Three?" and a drop down box appears with a list of possible reasons of which the user can choose from. And if the user only took Medicine Three, the system will display alert saying "Why didn't you taken Medicine One and Two?", and drop down box appears with a list of possible reasons. And if user has ticked all three checkbox, then display an alert saying "That great! Well Done!"
<form>
<input type="checkbox" name="a" value="one">Medicine One<br>
<input type="checkbox" name="b" value="two">Medicine Two<br>
<input type="checkbox" name="c" value="three">Medicine Three<br>
<input id=xbutton type="button" onClick="validate()" value="Submit">
</form>
I know how to do validation for one checkbox (like a terms agreement checkbox), but I'm a bit confused as to how to incorporate so many validation rules into one function.
Use querySelectorAll to iterate all the checkbox elements and check the .checked property.
Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
input[type="checkbox"]:not(:checked) will select only those elements which are not checked.
function validate() {
var msg = [];
[].forEach.call(document.querySelectorAll('input[type="checkbox"]:not(:checked)'), function(elem, index) {
msg.push(elem.name);
});
alert(msg.length ? 'Please check ' + msg.join(' and ') : 'All are checked!');
}
<form>
<input type="checkbox" name="a" value="one">Medicine One
<br>
<input type="checkbox" name="b" value="two">Medicine Two
<br>
<input type="checkbox" name="c" value="three">Medicine Three
<br>
<input id=xbutton type="button" onClick="validate()" value="Submit">
</form>
Fiddle here
Using jquery can help you to make things easy.
Here is the fiddle: https://jsfiddle.net/swaprks/zs7tpuo0/
HTML:
<form>
<input type="checkbox" name="a" value="one">Medicine One<br>
<input type="checkbox" name="b" value="two">Medicine Two<br>
<input type="checkbox" name="c" value="three">Medicine Three<br>
<input id=xbutton type="button" value="Submit">
</form>
JAVASCRIPT:
$("#xbutton").click(function(){
validate();
});
function validate(){
if ( $('input[type="checkbox"]:not(:checked)').length == 3 ) {
alert("Select atleast one option.");
}
}

Change checkbox state based on multiple conditions in AngularJS

In my scenario I have a select dropdown with an ng-model assigned to it. Each item in the dropdown corresponds to a number of checkboxes that are checked when a selection is made. The difficulty is that I can't just check for a simple key:value because checkboxes aren't exclusive to any particular selection. For example:
<select>
<option>Dog</option>
<option>Cat</option>
<option>Bird</option>
</select>
<input type="checkbox">Is an animal
<input type="checkbox">Can bark
<input type="checkbox">Can meow
<input type="checkbox">Can tweet
<input type="checkbox">Has four legs
<input type="checkbox">Has wings
So as you can, the checkboxes for "Is an animal" and "Has four legs" aren't exclusive. My current implementation uses a simple conditional expression to evaluate whether or not the checkbox is marked (ng-checked="animal=='dog'") but of course this excludes the other two possibilities. So I'm wondering if there's a native Angular way to handle OR statements or an array. Or if not, how can I go about this with JavaScript or jQuery?
See this fiddle: http://jsfiddle.net/QHza7/
Template:
<div ng-app ng-controller="Test">
<select ng-model="opts" ng-options="a.opts as a.name for a in answers"></select>
<br/>
<input type="checkbox" ng-model="opts.animal" />Is an animal<br/>
<input type="checkbox" ng-model="opts.bark" />Can bark<br/>
<input type="checkbox" ng-model="opts.meow" />Can meow<br/>
<input type="checkbox" ng-model="opts.tweet" />Can tweet<br/>
<input type="checkbox" ng-model="opts.legs4" />Has four legs<br/>
<input type="checkbox" ng-model="opts.wings" />Has wings<br/>
</div>
Code:
function Test($scope) {
$scope.answers = [
{name:"Dog", opts:{animal:true,bark:true,legs4:true}},
{name:"Cat", opts:{animal:true,meow:true,legs4:true}},
{name:"Bird", opts:{animal:true,tweet:true,wings:true}}
];
$scope.opts = null;
}

Categories

Resources