I am creating a review-control and using radiobutton for grade selection. I wrote some simple js to add a diffrent class when a radiobutton is checked.
The problem is that you can check every radio button, I want the user only to check one value. I writing this in javascript, but jQuery is welcome or a smartare solution.
Demo : http://jsfiddle.net/cbqt8/5/
HTML:
<div class="reviews">
<label class="input-check">
<input onchange="change_state(this)" type="radio" value="1" name="review[rating]" /> Bad
</label>
<label class="input-check">
<input onchange="change_state(this)" type="radio" value="2" name="review[rating]" /> Its okey
</label>
<label class="input-check">
<input onchange="change_state(this)" type="radio" value="3" name="review[rating]" /> Great
</label>
<label class="input-check">
<input onchange="change_state(this)" type="radio" value="4" name="review[rating]" /> Awesome
</label>
<label class="input-check">
<input onchange="change_state(this)" type="radio" value="5" name="review[rating]" />Super
</label>
</div>
JavaScript:
function change_state(obj) {
if (obj.checked) {
//if radiobutton is being checked, add a "checked" class
obj.parentNode.classList.add("checked");
}
else {
//else remove it
obj.parentNode.classList.remove("checked");
}
}
CSS:
/*reviews box*/
.reviews{
padding: 25px;
margin:0;
}
/*this is the style of an radio "button"*/
.input-check {
display: inline-block;
height:20px;
padding:5px 8px;
background:green;
width:90px;
color:white;
text-align: center;
}
/* This is the style for a radio "button" */
.input-check.checked{
background:red;
color:black;
font-weight:bold;
}
/*Hide the radiobutton*/
.input-check input {
display:none;
}
You got to remove the checked class for previously checked item.
jsFiddle: http://jsfiddle.net/P8jB8/
function change_state(obj) {
if (obj.checked) {
var checkedNodes = getElementsByClassName(document, "checked");
for (var i=0;i<checkedNodes.length;i++) {
checkedNodes[i].classList.remove("checked");
}
//if radiobutton is being checked, add a "checked" class
obj.parentNode.classList.add("checked");
}
else {
//else remove it
obj.parentNode.classList.remove("checked");
}
}
function getElementsByClassName(node,classname) {
if (node.getElementsByClassName) { // use native implementation if available
return node.getElementsByClassName(classname);
} else {
return (function getElementsByClass(searchClass,node) {
if ( node == null )
node = document;
var classElements = [],
els = node.getElementsByTagName("*"),
elsLen = els.length,
pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)"), i, j;
for (i = 0, j = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
})(classname, node);
}
}
Related
HTML5 form validation will not cover the situation where, starting from a group of checkboxes, at least one of them is checked. If a checkbox has the required attribute it must be checked, this is what I can get at most.
So I built a workaround that works fine (code in the snippet). The issue is that this works for one group of checkboxes. But I want my code to be valid even if I add more chackboxes groups. I need a suggestion on how to make it valid for multiple groups.
Any idea?
function bindItemsInput() {
var inputs = document.querySelectorAll('[name="option[]"]')
var radioForCheckboxes = document.getElementById('radio-for-checkboxes')
function checkCheckboxes () {
var isAtLeastOneServiceSelected = false;
for(var i = inputs.length-1; i >= 0; --i) {
if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
}
radioForCheckboxes.checked = isAtLeastOneCheckboxSelected
}
for(var i = inputs.length-1; i >= 0; --i) {
inputs[i].addEventListener('change', checkCheckboxes)
}
}
bindItemsInput() // call in window onload
.checkboxs-wrapper {
position: relative;
}
.checkboxs-wrapper input[name="radio-for-required-checkboxes"] {
position: absolute;
margin: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-appearance: none;
pointer-events: none;
border: none;
background: none;
}
<form>
<div class="checkboxs-wrapper">
<input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
<input type="submit" value="submit"/>
</form>
A second snippet with the relevant HTML (not working, goal of the question is to fix this). It will have now the same ID for the radio button: that is invalid and is the reason of the question:
function bindItemsInput() {
var inputs = document.querySelectorAll('[name="option[]"]')
var radioForCheckboxes = document.getElementById('radio-for-checkboxes')
function checkCheckboxes () {
var isAtLeastOneServiceSelected = false;
for(var i = inputs.length-1; i >= 0; --i) {
if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
}
radioForCheckboxes.checked = isAtLeastOneCheckboxSelected
}
for(var i = inputs.length-1; i >= 0; --i) {
inputs[i].addEventListener('change', checkCheckboxes)
}
}
bindItemsInput() // call in window onload
.checkboxs-wrapper {
position: relative;
}
.checkboxs-wrapper input[name="radio-for-required-checkboxes"] {
position: absolute;
margin: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-appearance: none;
pointer-events: none;
border: none;
background: none;
}
<form>
<div class="checkboxs-wrapper">
<input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
<div class="checkboxs-wrapper">
<input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
<input type="checkbox" name="products[]" value="option1"/>
<input type="checkbox" name="products[]" value="option2"/>
<input type="checkbox" name="products[]" value="option3"/>
</div>
<input type="submit" value="submit"/>
</form>
The form will be valid if at least on products[] checkbox and one option[] checkbox is checked. So I need the javascript to run indipendently for option[] and for products[]. If I have selected one item in groups[] but none in products[] then only products will be surrounded by the box and marked for completition
So this what I imagine you are looking for:
const myForm = document.forms['my-form']
myForm.addEventListener('change', bindItemsInput) // global change event listener
function bindItemsInput(e) //
{
if (!e.target.matches('div.checkboxs-wrapper input[type=checkbox]')) return
// to reject unconcerned checkbox
let groupDiv = e.target.closest('div.checkboxs-wrapper')
, radioGroup = groupDiv.querySelector('input[type=radio]')
, checkGroup = groupDiv.querySelectorAll('input[type=checkbox]')
;
radioGroup.checked = [...checkGroup].reduce((flag,chkBx)=>flag || chkBx.checked, false)
}
// ------ verification part-------------------
myForm.onsubmit=e=> // to verify
{
e.preventDefault() // disable submit for testing
console.clear()
// chexboxes checked values:
let options = [...myForm['option[]'] ].reduce((r,s)=>{ if (s.checked) r.push(s.value);return r},[])
, products = [...myForm['product[]'] ].reduce((r,s)=>{ if (s.checked) r.push(s.value);return r},[])
console.log('options = ', JSON.stringify( options ))
console.log('products = ', JSON.stringify( products ))
myForm.reset() // clear anything for new testing
console.log(' form reseted')
}
<form name="my-form">
<div class="checkboxs-wrapper">
<input type="radio" name="rGroup_1" required >
<input type="checkbox" name="option[]" value="option1">
<input type="checkbox" name="option[]" value="option2">
<input type="checkbox" name="option[]" value="option3">
</div>
<div class="checkboxs-wrapper">
<input type="radio" name="rGroup_2" required>
<input type="checkbox" name="product[]" value="product1">
<input type="checkbox" name="product[]" value="product2">
<input type="checkbox" name="product[]" value="product3">
</div>
<button type="submit">submit</button>
</form>
if i understant. so you have to give another id and another name of course, try this:
function bindItemsInput() {
var inputs = $("input[type=checkbox]");
var radios = $("input[type=radio]");
function checkCheckboxes () {
var isAtLeastOneServiceSelected = false;
for(var i = inputs.length-1; i >= 0; --i) {
if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
}
radios.each( function(){
$(this).checked = $(this).siblings($("input[type=checkbox]:checked")).length > 0;
});
}
for(var i = inputs.length-1; i >= 0; --i) {
inputs[i].addEventListener('change', checkCheckboxes)
}
}
Using jQuery this can be done with a lot less code.
$(document).ready(function() {
var checkCheckboxesInSameGroup = function() {
var inputs = $(this).children("input[name='option[]']");
var radio = $(this).children("input[name^='radio-for-group']")[0];
radio.checked = inputs.is(":checked");
};
$(".checkboxs-wrapper").on('change', checkCheckboxesInSameGroup);
});
.checkboxs-wrapper {
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div class="checkboxs-wrapper">
<input type="radio" name="radio-for-group1" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
<div class="checkboxs-wrapper">
<input type="radio" name="radio-for-group2" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
</form>
I'm not sure how to explain it. Hopefully my code is self-evident. I am fairly new to javascript.
<div>
<input type="checkbox" id="checkBox1" onclick="toggleCheckBox(this)">Check Box 1</input>
<div>
<input type="checkbox" id="checkBox2">Check Box 2</input>
</div>
</div>
function toggleCheckBox(checkBox1) {
// I've also tried 'checkBox1.parent' and 'checkBox1.parentElement'
var cb2 = checkBox1.parentNode.getElementByTagName('div').getElementByTagName('input');
if (checkBox1.checked == true) {
cb2.checked = true;
} else {
cb2.checked = false;
};
};
I keep getting checkBox1.parent is undefined.
Edit:
final desired out come:
<div id="a">
<input type="checkbox" onclick="toggleCheckBox(this)">Check Box 1</input>
<div>
<input type="checkbox">Check Box 2</input>
<input type="checkbox">Check Box 3</input>
</div>
</div>
<div id="b">
<input type="checkbox" onclick="toggleCheckBox(this)">Check Box 1</input>
<div>
<input type="checkbox">Check Box 2</input>
<input type="checkbox">Check Box 3</input>
</div>
</div>
and so on.
Edit: Parent Indeterminate
I got the parent to go to indeterminate, but it won't leave unless you click it.
/* clicked child checkbox */
var parentId = clickedBox.dataset.parent;
var checkedTrue = false;
var checkedFalse = false;
var checkState = clickedBox.checked;
Array.prototype.slice.call(allCheckboxes).forEach(function(checkbox) {
/* search checkboxes having same data-parent as clickedBox and is not checked */
if (parentId === checkbox.dataset.parent && !checkbox.checked) {
checkedFalse = true;
checkState = false;
return false;
} else if (parentId === checkbox.dataset.parent && checkbox.checked) {
checkedTrue = true;
return false;
}
});
/* search parent checkbox of clickedBox */
Array.prototype.slice.call(allCheckboxes).forEach(function(parentBox) {
if (parentBox.id === parentId) {
if (checkedTrue === true && checkedFalse === true) {
parentBox.indeterminate = true;
return false;
} else {
parentBox.checked = checkState;
return false;
}
}
});
In-case use of HTML5 data-* is not an constraint, this solution works with most of updated browsers including IE 11. Here, I am using data-parent attribute(having value same as id of parent) to link checkbox with its parent checkbox. Value -1 for data-parent denotes that there is no parent for the given checkbox.
let allCheckboxes;
/* checkbox click handler */
let toggleCheck = function(e) {
e.stopPropagation();
var clicked = this;
/* clicked ones is the parent */
if ('-1' === clicked.dataset.parent) {
/* search child checkboxes having data-parent=id of clicked ones */
Array.prototype.slice.call(allCheckboxes).forEach(function(c) {
if (c.dataset.parent === clicked.id) {
/* set checked state same as clicked ones */
c.checked = clicked.checked;
}
});
} else {
/* clicked ones is child checkbox */
var parentId = clicked.dataset.parent;
var checkState = clicked.checked;
Array.prototype.slice.call(allCheckboxes).forEach(function(c) {
/* search checkboxes having data-parent same as clicked ones and is not checked */
if (parentId === c.dataset.parent && !c.checked) {
checkState = false;
return false;
}
});
/* search parent checkbox of clicked ones */
Array.prototype.slice.call(allCheckboxes).forEach(function(c) {
if (c.id === parentId) {
c.checked = checkState;
return false;
}
});
}
};
/* wait till DOM renderes and available to bind event listneres */
document.addEventListener('DOMContentLoaded', function() {
/* fetch all checkboxes having attributes data-parent and id */
allCheckboxes = document.querySelectorAll('input[type=checkbox][data-parent][id]');
/* iterate over all checkboxed to bind click listeners */
Array.prototype.slice.call(allCheckboxes).forEach(function(c) {
c.addEventListener('click', toggleCheck);
});
});
div {
margin-left: 1.5rem;
}
<div>
<label><input type="checkbox" data-parent="-1" id="c1"/>Check Box 1</label>
<div>
<label><input type="checkbox" data-parent="c1" id="c2">Check Box 2</label>
<label><input type="checkbox" data-parent="c1" id="c3">Check Box 3</label>
</div>
</div>
<div>
<label><input type="checkbox" data-parent="-1" id="c4">Check Box 1</label>
<div>
<label><input type="checkbox" data-parent="c4" id="c5">Check Box 2</label>
<label><input type="checkbox" data-parent="c4" id="c6">Check Box 3</label>
</div>
</div>
P.S. </input> is invalid tag.
Edited: Regarding checkState since as of now I have not provided any intermediate state for parent checkbox, so what I did is took the checked state of clicked child checkbox, if its checked then searched from the list of other remaining child checkboxes having same parent id. When encountered anymore child checkboxes which is not checked then I simply mark parent checkbox as unchecked.
With intermediate: Well, its not that fancy but does the trick.
let allCheckboxes;
let repeat = Array.prototype.slice;
let applyState = function(checkbox, state) {
let classes = checkbox.parentNode.classList;
if (!state || !checkbox.checked) {
classes.remove("checked");
classes.remove("intermediate");
checkbox.dataset.state = 0;
}
if (1 === state || checkbox.checked) {
classes.add("checked");
checkbox.dataset.state = 1;
}
if (2 === state) {
classes.remove("checked");
classes.add("intermediate");
checkbox.dataset.state = 2;
}
}
/* checkbox click handler */
let toggleCheck = function(e) {
e.stopPropagation();
var clicked = this;
applyState(clicked);
/* clicked ones is the parent */
if ('-1' === clicked.dataset.parent) {
/* search child checkboxes having data-parent=id of clicked ones */
repeat.call(allCheckboxes).forEach(function(c) {
if (c.dataset.parent === clicked.id) {
/* set checked state same as clicked ones */
c.checked = clicked.checked;
applyState(c);
}
});
} else {
/* clicked ones is child checkbox */
var parentId = clicked.dataset.parent;
var check = 0,
uncheck = 0;
repeat.call(allCheckboxes).forEach(function(c) {
/* search checkboxes having data-parent same as clicked ones */
if (parentId === c.dataset.parent) {
if (c.checked) {
check++;
} else {
uncheck++;
}
}
});
/* search parent checkbox of clicked ones */
repeat.call(allCheckboxes).forEach(function(c) {
if (c.id === parentId) {
var state = 1;
if (0 === check) {
state = 0;
c.checked = false;
} else if (0 < uncheck) {
state = 2;
}
applyState(c, state);
return false;
}
});
}
};
/* wait till DOM renderes and available to bind event listneres */
document.addEventListener('DOMContentLoaded', function() {
/* fetch all checkboxes having attributes data-parent and id */
allCheckboxes = document.querySelectorAll('input[type=checkbox][data-parent][id]');
/* iterate over all checkboxed to bind click listeners */
repeat.call(allCheckboxes).forEach(function(c) {
c.addEventListener('click', toggleCheck);
});
});
div {
margin-left: 1.5rem;
}
label>input {
display: none;
}
label:before {
cursor: pointer;
content: "";
padding: 7px;
border: 1px solid #000;
background-color: #fff;
display: inline-block;
margin-left: 2px;
margin-right: 2px;
vertical-align: top;
}
label.checked:before,
label.intermediate:before {
color: blue;
border-color: blue;
}
label.checked:before {
content: "\2713";
padding: 0px 3px;
font-size: 10px;
}
label.intermediate:before {
content: "\2012";
padding: 0px 4px;
font-size: 11px;
}
<div>
<label><input type="checkbox" data-parent="-1" id="c1"/>Check Box 1</label>
<div>
<label><input type="checkbox" data-parent="c1" id="c2">Check Box 2</label>
<label><input type="checkbox" data-parent="c1" id="c3">Check Box 3</label>
</div>
</div>
<div>
<label><input type="checkbox" data-parent="-1" id="c4">Check Box 1</label>
<div>
<label><input type="checkbox" data-parent="c4" id="c5">Check Box 2</label>
<label><input type="checkbox" data-parent="c4" id="c6">Check Box 3</label>
</div>
</div>
Here's what I would do. One thing to note, this solution does not support IE11 or below, as it uses closest() to find parent nodes by a selector.
https://caniuse.com/#search=closest
(You may have to click the GIF to get it to play.)
<div data-checkbox-group>
<label><input type="checkbox" data-master-checkbox /> Master</label>
<div>
<label><input type="checkbox" /> Check Box 1</label><br>
<label><input type="checkbox" /> Check Box 2</label><br>
<label><input type="checkbox" /> Check Box 3</label><br>
<label><input type="checkbox" /> Check Box 4</label><br>
<label><input type="checkbox" /> Check Box 5</label><br>
</div>
</div>
<hr>
<div data-checkbox-group>
<label><input type="checkbox" data-master-checkbox /> Master</label>
<div>
<label><input type="checkbox" /> Check Box 1</label><br>
<label><input type="checkbox" /> Check Box 2</label><br>
<label><input type="checkbox" /> Check Box 3</label><br>
<label><input type="checkbox" /> Check Box 4</label><br>
<label><input type="checkbox" /> Check Box 5</label><br>
</div>
</div>
<hr>
<div data-checkbox-group>
<label><input type="checkbox" data-master-checkbox /> Master</label>
<div>
<label><input type="checkbox" /> Check Box 1</label><br>
<label><input type="checkbox" /> Check Box 2</label><br>
<label><input type="checkbox" /> Check Box 3</label><br>
<label><input type="checkbox" /> Check Box 4</label><br>
<label><input type="checkbox" /> Check Box 5</label><br>
</div>
</div>
<hr>
<script>
var toggleChecks = function() {
var isMaster = this.hasAttribute('data-master-checkbox')
var group = this.closest('[data-checkbox-group]')
var boxes = group.querySelectorAll('input[type=checkbox]:not([data-master-checkbox])')
var master = isMaster ? this : group.querySelector('input[type=checkbox][data-master-checkbox]')
if (isMaster) {
// Set all children to the value of the parent
for(var i = 0; i < boxes.length; i++) {
boxes[i].checked = this.checked
}
} else {
// Toggle all children to the state of the master
var checkedCount = 0
for(var i = 0; i < boxes.length; i++) {
if(boxes[i].checked) { checkedCount += 1 }
}
master.checked = checkedCount == boxes.length
master.indeterminate = !master.checked && !checkedCount == 0
}
}
var nodes = document.querySelectorAll('[data-checkbox-group] input[type=checkbox]')
for(var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('change', toggleChecks)
}
</script>
I have the following jquery code where i want to remove the value from the textfield if the checkbox is unchecked and add if it is checked.
initially all the values comes in the textbox as the ^ seperator. and all checkboxes checked
here is y piece of code:
$(document).on('change','._invoice',function() {
var mystr = $(this).attr('data-id').is(":checked");
if(mystr) {
var returnVal = confirm("Are you sure?");
$(this).attr("checked", returnVal);
}
});
});
Text field values and i also want to remove the separator and add the name at the last with ^ as separator.
Robert Berenson^Nancy Foster^Richard Gourhan^LORI HEDMAN^Pui Hoang^Linda Lee^Kristen McDonald^Matthew Miller^Tricia Roland^Terry West
A simple way is that change text of textbox on checkbox change event. Then means you need to get text of every checked checkbox and set it to textbox, when any checkbox is changed.
$(".check").change(function(){
var text = "";
$(".check:checked").each(function(){
text += text != "" ? "^" : "";
if ($(this).prop("checked"))
text += $(this).val();
});
$(".text").val(text);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" class="check" value="Text1" />
<input type="checkbox" class="check" value="Text2" />
<input type="checkbox" class="check" value="Text3" />
<input type="checkbox" class="check" value="Text4" />
<input type="checkbox" class="check" value="Text5" />
<br/>
<input type="text" class="text" />
var txt = document.getElementById( 'droptxt' ),
content = document.getElementById( 'content' ),
list = document.querySelectorAll( '.content input[type="checkbox"]' ),
quantity = document.querySelectorAll( '.quantity' );
txt.addEventListener( 'click', function() {
content.classList.toggle( 'show' )
} )
window.onclick = function( e ) {
if ( !e.target.matches( '.list' ) ) {
if ( content.classList.contains( 'show' ) ) content.classList.remove( 'show' )
}
}
list.forEach( function( item, index ) {
item.addEventListener( 'click', function() {
calc()
} )
} )
function calc() {
for ( var i = 0, arr = []; i < list.length; i++ ) {
let spanArray = [];
document.querySelectorAll('span').forEach(element => {
spanArray.push(element.innerHTML);
});
if ( list[ i ].checked ) arr.push( list[ i ].value + " "+ spanArray)
}
txt.value = arr.join(', ')
}
h1 {
color: #0000ff;
}
#droptxt {
padding: 8px;
width: 300px;
cursor: pointer;
box-sizing: border-box
}
.dropdown {
position: relative;
display: inline-block
}
.content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 200px;
overflow: auto;
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, .2);
z-index: 1
}
.content div {
padding: 10px 15px
}
.content div:hover {
background-color: #ddd
}
.show {
display: block
}
<h1>KIAAT</h1>
<b>Adding/Removing Checkbox Values into TextArea</b>
<br><br>
<input type="text" id="droptxt" class="list" placeholder="Select the values" readonly>
<div id="content" class="content">
<div id="market" class="list">
<label><input type="checkbox" id="market" class="list" value="apple" /> Apple</label>
</div>
<div class="list">
<label><input type="checkbox" id="banana" class="list" value="Banana" /> Banana</label>
</div>
<div class="list">
<label><input type="checkbox" id="pineapple" class="list" value="Pineapple" /> Pineapple</label>
</div>
</div>
I need a form with multiple steps where the first step restricts options in the successive steps.
So below is an example of use:
User selects from 4 global options
If user selects option 1
Then the user can only select 8 options (no more no less) from a multiple choice box.
If user select option 2
Then the user can only select 10 options (no more no less) from a multiple choice box.
Same is the case with options 3 and 4
After all these selections, this form has to show a final price based on the options user selected in the FIRST STEP. No matter what choices were selected in successive steps.
When this form shows final price, user has to click SUBMIT button and send this result with all these options through an email.
Can someone help me in figuring out the javascript required to do this? Most important thing right now for me is to figure out 'restrictions codes' in multiple items choice boxes.
This is the form I was thinking about:
<form action="" id="menuform" onsubmit="return false;">
<fieldset>
<legend>Select one of this four menus</legend>
<label >Menu Option</label>
<input type="radio" name="selectedmenu" value="Menu1"
onclick="calculateTotal()" />
Menu 1 - serves 8 courses ($20)
<input type="radio" name="selectedmenu" value="Menu2"
onclick="calculateTotal()" />
Menu 2 - serves 12 courses ($25)
<input type="radio" name="selectedmenu" value="Menu3"
onclick="calculateTotal()" />
Menu 3 - serves 16 courses ($35)
<input type="radio" name="selectedmenu" value="Menu4"
onclick="calculateTotal()" />
Menu 4 - serves 30 courses ($75)
<label >Filling</label>
<select id="filling" name='filling'
onchange="calculateTotal()">
<option value="dish1">Dish 1 ($1)</option>
<option value="dish2">Dish 2 ($5)</option>
<option value="dish3">Dish 3 ($5)</option>
(more...)
</select>
<br/>
<div id="totalPrice"></div>
</fieldset>
</form>
Then, for Javascript code I was trying with this to store and return some values but my problem is how to force to select an exact number of options in the SECOND STEP:
var menu_prices = new Array();
menu_prices["Menu1"]=20;
menu_prices["Menu2"]=25;
menu_prices["Menu3"]=35;
menu_prices["Menu4"]=75;
function getMenuPrice()
{
var menuPrice=0;
var theForm = document.forms["menuform"];
var selectedMenu = theForm.elements["selectedmenu"];
for(var i = 0; i < selectedMenu.length; i++)
{
if(selectedMenu[i].checked)
{
menuPrice = menu_prices[selectedMenu[i].value];
break;
}
}
return menuPrice;
}
function getTotal()
{
var menuPrice = getMenuPrice() + getOtherOptionsPrices();
document.getElementById('totalPrice').innerHTML =
"Total Price For Menu $"+menuPrice;
}
Structure your HTML markup carefully, which helps you to target elements via JavaScript easily. Especially, using data-attributes on radio buttons for quantity and price which could be then easily retrieved in respective event handlers. Something like this:
<form action="" method="post" id="menuform" name="menuform">
<fieldset>
<legend>Select menu option</legend>
<label>
<input type="radio" name="selectedmenu" checked value="menu01" data-qty='3' data-price='20' />
<span>1 - serves 3 courses ($20)</span>
</label>
...
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<select id="fillings" name="fillings" size="6" multiple>
<option value="1">Dish 1 ($1)</option>
...
<fieldset>
<legend>Checkout</legend>
<div id="totalPrice"></div>
<input type="submit" value="Submit" />
</fieldset>
<fieldset>
<legend>Messages</legend>
<p id="result"></p>
</fieldset>
</form>
Identify and select all elements that you'll need:
var menuform = document.getElementById('menuform'),
radios = document.getElementsByName('selectedmenu'),
fillings = document.getElementById('fillings'),
fillingsPrompt = document.getElementById('fillingsPrompt'),
totalPrice = document.getElementById('totalPrice'),
result = document.getElementById('result'),
fillingsAllowed = 0, currentSelection = [], currency = '$'
;
Add event listeners to your radio buttons, select, and the submit button:
menuform.addEventListener('submit', handleSubmit);
fillings.addEventListener('change', handleFillings);
for (var i = radios.length; i--; ) {
radios[i].addEventListener('change', handleLimit);
}
Code the actual event handlers:
// When radio buttons are selected, update parameters for limit
function handleLimit(e) { updateParameters(e.target); }
// When options are selected in the dropdown,
// check against the limit and reset the selection if it exceeds
function handleFillings(e) {
var count = getSelectedCount();
if (count > fillingsAllowed) { resetSelect(); }
else { currentSelection = getSelectedValues(); }
}
// When submit button is clicked,
// check the count of selection against the limit, and
// show appropriate error message
function handleSubmit(e) {
var count = getSelectedCount();
e.preventDefault();
if (count != fillingsAllowed) {
result.textContent = 'Must select exactly ' + fillingsAllowed + ' fillings!';
} else {
result.textContent = 'Ok. ';
}
}
And then code all the helper functions used in the handlers above:
function updateParameters(elem) {
// update the limit based on quantity data attribute on radio
fillingsAllowed = elem.getAttribute('data-qty');
// show the amount based on price data-attribute
totalPrice.textContent = 'Amount: ' + currency + elem.getAttribute('data-price');
// show the hint on legend of fieldset for selecting options
fillingsPrompt.textContent = 'Select ' + fillingsAllowed + ' fillings';
}
// iterate options and get count of selected ones
function getSelectedCount() {
var options = fillings.options, count = 0;
for (var i=0; i < options.length; i++) {
if (options[i].selected) count++;
}
return count;
}
// iterate options and get selected values in an array
function getSelectedValues() {
var options = fillings.options, values = [0];
for (var i=0; i < options.length; i++) {
if (options[i].selected) values.push(options[i].value);
}
return values;
}
// remove selection from all options, and
// re-select based on the array used in the previous function
function resetSelect() {
var options = fillings.options;
for (var i=0; i < options.length; i++) {
options[i].selected = false;
if (currentSelection.indexOf(options[i].value) != -1) {
options[i].selected = true;
}
}
}
Everything put together, the demo looks like this:
Fiddle: https://jsfiddle.net/abhitalks/L813qudw/
Snippet:
var menuform = document.getElementById('menuform'),
radios = document.getElementsByName('selectedmenu'),
fillings = document.getElementById('fillings'),
fillingsPrompt = document.getElementById('fillingsPrompt'),
totalPrice = document.getElementById('totalPrice'),
result = document.getElementById('result'),
fillingsAllowed = 0, currentSelection = [], currency = '$'
;
// listen to events
menuform.addEventListener('submit', handleSubmit);
fillings.addEventListener('change', handleFillings);
for (var i = radios.length; i--; ) {
radios[i].addEventListener('change', handleLimit);
}
// event handlers
function handleLimit(e) { updateParameters(e.target); }
function handleFillings(e) {
var count = getSelectedCount();
if (count > fillingsAllowed) { resetSelect(); }
else { currentSelection = getSelectedValues(); }
}
function handleSubmit(e) {
var count = getSelectedCount();
e.preventDefault();
if (count != fillingsAllowed) {
result.textContent = 'Must select exactly ' + fillingsAllowed + ' fillings!';
} else {
result.textContent = 'Ok. ';
}
}
// fire initial update based on the first radio
updateParameters(radios[0]);
// helper functions
function updateParameters(elem) {
fillingsAllowed = elem.getAttribute('data-qty');
totalPrice.textContent = 'Amount: ' + currency + elem.getAttribute('data-price');
fillingsPrompt.textContent = 'Select ' + fillingsAllowed + ' fillings';
}
function getSelectedCount() {
var options = fillings.options, count = 0;
for (var i=0; i < options.length; i++) {
if (options[i].selected) count++;
}
return count;
}
function getSelectedValues() {
var options = fillings.options, values = [0];
for (var i=0; i < options.length; i++) {
if (options[i].selected) values.push(options[i].value);
}
return values;
}
function resetSelect() {
var options = fillings.options;
for (var i=0; i < options.length; i++) {
options[i].selected = false;
if (currentSelection.indexOf(options[i].value) != -1) {
options[i].selected = true;
}
}
}
fieldset {
margin: 1vw; font-family: monospace;
display: inline-block; width: 40vw; vertical-align: top;
}
legend { color: #d33; padding: 0px 4px; }
legend::before { content: '[ '; }
legend::after { content: ' ]'; }
fieldset > label { display: block; margin: 4px 0px; }
fieldset input, fieldset span { vertical-align: middle; }
fieldset > select { width: 100%; font-family: monospace; }
input[type=submit] { margin-top: 12px; }
#totalPrice, #result {
height: 24px; line-height: 24px;
background-color: #dde; padding: 4px;
font-family: monospace;
}
#result { color: #d33; font-family: monospace; }
<form action="" method="post" id="menuform" name="menuform">
<fieldset>
<legend>Select menu option</legend>
<label>
<input type="radio" name="selectedmenu" checked
value="menu01" data-qty='3' data-price='20' />
<span>1 - serves 3 courses ($20)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu02" data-qty='4' data-price='25' />
<span>2 - serves 4 courses ($25)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu03" data-qty='5' data-price='35' />
<span>3 - serves 5 courses ($35)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu04" data-qty='6' data-price='75' />
<span>4 - serves 6 courses ($75)</span>
</label>
</fieldset>
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<select id="fillings" name="fillings" size="6" multiple>
<option value="1">Dish 1 ($1)</option>
<option value="2">Dish 2 ($5)</option>
<option value="3">Dish 3 ($5)</option>
<option value="4">Dish 4 ($1)</option>
<option value="5">Dish 5 ($5)</option>
<option value="6">Dish 6 ($5)</option>
</select>
</fieldset>
<fieldset>
<legend>Checkout</legend>
<div id="totalPrice"></div>
<input type="submit" value="Submit" />
</fieldset>
<fieldset>
<legend>Messages</legend>
<p id="result"></p>
</fieldset>
</form>
<hr>
...how can I change <option> and use <input type="checkbox">
instead for the SECOND STEP?
In order to use checkboxes instead of select, no major changes are required.
Changed mark-up:
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<label>
<input type='checkbox' name='fillings' value="1" />
<span>Dish 1 ($5)</span>
</label>
...
JavaScript changes:
Adding the event-handlers for checkboxes instead of select, would require just iterating over those:
(just like the radios already done)
for (var i = fillings.length; i--; ) {
fillings[i].addEventListener('change', handleFillings);
}
In all the helper functions, remove the variable declaration for options:
(as it is now no longer required)
var options = fillings.options
And, In all the helper functions,
change: options.length and options[i].selected
to, fillings.length and fillings[i].checked respectively.
That's it.
Fiddle 2: https://jsfiddle.net/abhitalks/hp88wdfc/
Snippet 2:
var menuform = document.getElementById('menuform'),
radios = document.getElementsByName('selectedmenu'),
fillings = document.getElementsByName('fillings'),
fillingsPrompt = document.getElementById('fillingsPrompt'),
totalPrice = document.getElementById('totalPrice'),
result = document.getElementById('result'),
fillingsAllowed = 0, currentSelection = [], currency = '$'
;
// listen to events
menuform.addEventListener('submit', handleSubmit);
for (var i = fillings.length; i--; ) {
fillings[i].addEventListener('change', handleFillings);
}
for (var i = radios.length; i--; ) {
radios[i].addEventListener('change', handleLimit);
}
// event handlers
function handleLimit(e) { updateParameters(e.target); }
function handleFillings(e) {
var count = getSelectedCount();
if (count > fillingsAllowed) { resetSelect(); }
else { currentSelection = getSelectedValues(); }
}
function handleSubmit(e) {
var count = getSelectedCount();
e.preventDefault();
if (count != fillingsAllowed) {
result.textContent = 'Must select exactly ' + fillingsAllowed + ' fillings!';
} else {
result.textContent = 'Ok. ';
}
}
// fire initial update based on the first radio
updateParameters(radios[0]);
// helper functions
function updateParameters(elem) {
fillingsAllowed = elem.getAttribute('data-qty');
totalPrice.textContent = 'Amount: ' + currency + elem.getAttribute('data-price');
fillingsPrompt.textContent = 'Select ' + fillingsAllowed + ' fillings';
}
function getSelectedCount() {
var count = 0;
for (var i=0; i < fillings.length; i++) {
if (fillings[i].checked) count++;
}
return count;
}
function getSelectedValues() {
var values = [0];
for (var i=0; i < fillings.length; i++) {
if (fillings[i].checked) values.push(fillings[i].value);
}
return values;
}
function resetSelect() {
for (var i=0; i < fillings.length; i++) {
fillings[i].checked = false;
if (currentSelection.indexOf(fillings[i].value) != -1) {
fillings[i].checked = true;
}
}
}
fieldset {
margin: 1vw; font-family: monospace;
display: inline-block; width: 40vw; vertical-align: top;
}
legend { color: #d33; padding: 0px 4px; }
legend::before { content: '[ '; }
legend::after { content: ' ]'; }
fieldset:first-of-type > label { display: block; margin: 4px 0px; }
fieldset:nth-of-type(2) > label {
display: inline-block; width: 45%;
}
fieldset input, fieldset span { vertical-align: middle; }
input[type=submit] { margin-top: 12px; }
#totalPrice, #result {
height: 24px; line-height: 24px;
background-color: #dde; padding: 4px;
font-family: monospace;
}
#result { color: #d33; font-family: monospace; }
<form action="" method="post" id="menuform" name="menuform">
<fieldset>
<legend>Select menu option</legend>
<label>
<input type="radio" name="selectedmenu" checked
value="menu01" data-qty='3' data-price='20' />
<span>1 - serves 3 courses ($20)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu02" data-qty='4' data-price='25' />
<span>2 - serves 4 courses ($25)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu03" data-qty='5' data-price='35' />
<span>3 - serves 5 courses ($35)</span>
</label>
<label>
<input type="radio" name="selectedmenu"
value="menu04" data-qty='6' data-price='75' />
<span>4 - serves 6 courses ($75)</span>
</label>
</fieldset>
<fieldset>
<legend id='fillingsPrompt'>Select fillings</legend>
<label>
<input type='checkbox' name='fillings' value="1" />
<span>Dish 1 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="2" />
<span>Dish 2 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="3" />
<span>Dish 3 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="4" />
<span>Dish 4 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="5" />
<span>Dish 5 ($5)</span>
</label>
<label>
<input type='checkbox' name='fillings' value="6" />
<span>Dish 6 ($5)</span>
</label>
</fieldset>
<fieldset>
<legend>Checkout</legend>
<div id="totalPrice"></div>
<input type="submit" value="Submit" />
</fieldset>
<fieldset>
<legend>Messages</legend>
<p id="result"></p>
</fieldset>
</form>
<hr>
I need to seperate the checked and unchecked check box from set of check boxes. i have done half-of-work but i can't able to separate the checked and unchecked checkbox. please help me out.
Below example has the merge button. when clicked on the merge button. it has to be separate the checked and unchecked checkbox.
$('document').ready( function() {
var b = $('#hid').val();
for (var i=0; i<b; i++) {
var data ="<li><input type='checkbox' id='"+i+"'>Example"+i+"</li>";
$('#aa').append(data);
//$('td').css({'border-right':'1px solid red', ''});
$('.checklist').append(data);
}
//var a = $('input[type="checkbox"]').length;
//$('input[type="checkbox"]').attr("checked");
//if ($(this).is(':checked')) {
//}
/* for (j=0; j<a; j++)
{
var che = $("input[type=checkbox]:checked").length;
alert (che);
if(che > 3))
{
alert ('this is 2');
} else {
alert('you clicked more than four');
}
}*/
$('#mer').click( function() {
var che = $('input[type="checkbox"]:checked').filter(":checked").length;
//alert($('input[type="checkbox"]:checked').filter(":not(:checked)").length);
$('input[type="checkbox"]:checked').attr('disabled', true);
});
/*
for (var j=0; j<=b; j++) {
function isEven(j) {
if (j%2 == 0)
alert(j);
return true;
else
return false;
}
}
*/
/* $(function() {
$('input[type="checkbox"]').bind('click',function() {
if($('input[type="checkbox"]:checked').length == 2) {
$(':checked').attr('disabled', true);
}
});
});
*/
});
</script>
<style type="text/css">
.wrapper {
width:900px;
height:auto;
margin:0 auto;
}
.checklist {
margin:0px;
padding:0px;
}
ul.checklist {
margin:0px;
padding:0px;
}
ul.checklist li {
list-style-type:none;
}
.dull {
color:#ccc;
}
</style>
</head>
<body>
<div class="wrapper">
<input type="hidden" name="no. of checkbox" value="15" id="hid"/>
<ul class="checklist">
</ul>
<input type="button" value="merge" id="mer" />
</div>
</body>
</html>
Perhaps something like:
var unchecked = [];
var checked = [];
jQuery.each($('input[type="checkbox"]'), function() {
if (this.checked) {
checked.push(this);
}
else {
unchecked.push(this);
}
});
You can select checked with:
$(":checkbox:checked")
And not checked with:
$(":checkbox:not(:checked)")
Hope this helps. Cheers
$('#mer').click( function() {
var checked = [];
var unchecked = [];
$('input[type="checkbox"]').each(function(){
if( this.checked ){
checked.push(this);
}else{
unchecked.push(this);
}
});
});
I'm not sure to understand what you want to accomplish. From your comments it seems to me that you need something like this (replace your div.wrapper with mine and add the jQuery code before the end of your body):
HTML code (div.wrapper) :
<div class="wrapper">
<form action="#" method="get" accept-charset="utf-8">
<ul class="checkboxes">
<li><label for="chk_1">chk_1</label>
<input type="checkbox" name="chk1" value="" id="chk_1">
</li>
<li><label for="chk_2">chk_2</label>
<input type="checkbox" name="chk2" value="" id="chk_2">
</li>
<li><label for="chk_3">chk_3</label>
<input type="checkbox" name="chk3" value="" id="chk_3">
</li>
<li><label for="chk_4">chk_4</label>
<input type="checkbox" name="chk4" value="" id="chk_4">
</li>
<li><label for="chk_5">chk_5</label>
<input type="checkbox" name="chk5" value="" id="chk_5">
</li>
<li><label for="chk_6">chk_6</label>
<input type="checkbox" name="chk6" value="" id="chk_6">
</li>
</ul>
<input type="button" value="merge" id="mer" />
</form>
jQuery code:
<script type="text/javascript" charset="utf-8">
$('document').ready( function() {
$('#mer').click( function() {
var checked = $(':checkbox:checked').parents("li").remove();
checked.insertBefore($(".checkboxes li:first"));
});
});
</script>