HI,
I have an HTML which has several a list of items with a checkbox (these are placed in a table). Each row in the table has the following coloumn:
<input type='checkbox' name='Events[]' value='1'>
<input type='checkbox' name='Events[]' value='2'>
etc
I would like to have make a link names "select all" that when clicked will select all the items.
I am using the following JS, but it is not working.
function SelectAll(form)
{
for(var i in form.Events.childNodes)
if(form.Events.childNodes[i].type == "checkbox")
form.Events.childNodes[i].checked = true;
}
The name of your input is Events[], so form.Events wouldn't find it
Because square brackets don't fit in JavaScript o.p property access shortcut, you would have to use the explicit string-based notation to get them:
var inputs= form.elements['Events[]'];
the form.elements collection (and the form collection itself—form['Events[]']—which is a non-standardised shortcut to the same thing but with more chance of name clashes) is a bit old-school and has some disadvantages like returning a single element instead of a list when there's only one element. You'd probably be better off using getElementsByName:
var inputs= form.getElementsByName('Events[]');
either way, follow up with:
for (var i= inputs.length; i-->0;)
inputs.checked= true;
Never use for...in to iterate an Array or array-like sequence. It doesn't do what you think at all. Stick to the old-school indexed loop.
Here you go this should work
<input class="Events" type='checkbox' name='Events[]' value='1'>
<input class="Events" type='checkbox' name='Events[]' value='2'>
function SelectAll(form) {
for (var i = 0; i < form.elements.length; i ++) {
if (form.elements[i].type == "checkbox" && form.elements[i].className="Events") {
form.elements[i].checked = true;
}
}
)
That will only work for checkboxes that are directly in the <form> tag, and not nested inside any other tags.
The simplest way to do this is to use jQuery:
$(':checkbox', form).attr('checked', true);
Related
This simple code checks if there is at lease one check box marked,
When I try to get check box array with Firefox I don't- I just the first one,
Same code working fine in IE,
Do I need to make different ID's for the check box elements and iterate them?
Thanks for your help.
<html>
<head>
<script type="text/javascript">
function testCheckBox(){
var vehicle = document.getElementById('vehicle');
for (var i=0; i < vehicle.length; i++){
alert(vehicle[i].checked);
if (trucks[i].checked){
alert('at least one was selected');
return true;
}
}
alert('Please select one');
return false;
}
</script>
</head>
<body>
<form>
<input type="checkbox" name="vehicle" value="Bike" /> I have a bike<br />
<input type="checkbox" name="vehicle" value="Car" /> I have a car
<br />
<input type="button" name="test" value="test" onclick="testCheckBox();" />
</body>
</html>
getElementById() never returns an array. It only returns a single element (because ids must be unique - i.e. having more than one element with the same id is invalid HTML.) getElementsByTagName() is what you want here:
var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var el = inputs[i];
if (el.type == 'checkbox' && el.checked) {
alert(el.value + ' is checked');
}
}
(Note: newer browsers support getElementsByClassName, which could also be used.
The problem is that you don't have any element with that id in your HTML. That's a semantic issue. And as you are using checkboxes, I don't think that getElementById is the way to go. You should either use the class attribute or add a containing element for those checkboxes and then iterate over its children elements (the checkboxes).
I wouldn't count on browsers allowing the name attribute as a substitute for IDs. If you assign all of your checkboxes a unique ID, you could just use some conditional checks to see if any of them are checked individually, such as:
function testCheckBox() {
var bikeCB = document.getElementById('bikeCB');
var carCB = document.getElementById('carCB');
if(bikeCB.checked) {
alert('An item is checked');
}else if(carCB.checked) {
alert('An item is checked');
}else { //after all have been checked
alert('No items are checked');
}
}
While you would need to add an ID for each checkbox in the HTML:
<input type="checkbox" id="bikeCB" value="Bike" /> I have a bike<br />
<input type="checkbox" id="carCB" value="Car" /> I have a car
If you are intent on looping through the checkboxes, you could give your form an ID and use the form.elements[] collection to loop through them and test for one being checked:
function testCheckBox() {
var form = document.getElementById('form1'); //get reference to form
var length = form.elements.length; //get length of form.elements array
for(i=0; i<length; i++) { //loop through while i is less than array length
if(form.elements[i].checked) {
alert('An item was checked');
}
}
}
This will alert for every checkbox that is checked. If you just wanted to know once if any were checked, you could possibly set a variable to true if any were checked, and then check if the variable was true after the for loop to know whether to alert or not.
By the way, you appear to be missing a closing </form> tag in your html after the <input> elements.
What you need is getElementsByName, not getElementById.
If you want to select by tag name, it's getElementsByTagName. If it's class names you want, getElementsByClassName (newer browsers only). You see? So use the right method depending on what you're selecting by.
I have a list of products, each individual product has a checkbox value with the products id e.g. "321". When the products checkbox is checked (can be more than 1 selected) i require the value to be collected. Each product will also have a input text field for defining the Qty e.g "23" and i also require this Qty value to be collected. The Qty text input should only be collected if the checkbox is checked and the qty text value is greater than 1. The plan is to collect all these objects, put them in to a loop and finally turn them in to a string where i can then display the results.
So far i have managed to collect the checkbox values and put these into a string but i'm not sure how to collect the additional text Qty input values without breaking it. My understanding is that document.getElementsByTagName('input') is capable of collecting both input types as its basically looking for input tags, so i just need to work out how to collect and loop through both the checkboxes and the text inputs.
It was suggested that i use 2 if statements to accomplish this but i'm new to learning javascript so i'm not entirely sure how to go about it. I did try adding the if statement directly below the first (like you would in php) but this just seemed to break it completely so i assume that is wrong.
Here is my working code so far that collects the checkbox values and puts them in a string. If you select the checkbox and press the button the values are returned as a string. Please note nothing is currently appended to qty= because i dont know how to collect and loop the text input (this is what i need help with).
How can i collect the additional qty input value and append this number to qty=
// function will loop through all input tags and create
// url string from checked checkboxes
function checkbox_test() {
var counter = 0, // counter for checked checkboxes
i = 0, // loop variable
url = '/urlcheckout/add?product=', // final url string
// get a collection of objects with the specified 'input' TAGNAME
input_obj = document.getElementsByTagName('input');
// loop through all collected objects
for (i = 0; i < input_obj.length; i++) {
// if input object is checkbox and checkbox is checked then ...
if (input_obj[i].type === 'checkbox' && input_obj[i].checked) {
// ... increase counter and concatenate checkbox value to the url string
counter++;
url = url + input_obj[i].value + '&qty=' + '|';
}
}
// display url string or message if there is no checked checkboxes
if (counter > 0) {
// remove first "&" from the generated url string
url = url.substr(1);
// display final url string
alert(url);
}
else {
alert('There is no checked checkbox');
}
}
<ul>
<li>
<form>
<input type="checkbox" id="checked-product" name="checked-product" value="311">Add To Cart
<div class="quantity">
<input type="text" name="qty" id="qty" maxlength="12" value="1" class="input-text qty"/>
</div>
</form>
</li>
<li>
<form>
<input type="checkbox" id="checked-product" name="checked-product" value="321">Add To Cart
<div class="quantity">
<input type="text" name="qty" id="qty" maxlength="12" value="10" class="input-text qty"/>
</div>
</form>
</li>
<li>
<form>
<input type="checkbox" id="checked-product" name="checked-product" value="98">Add To Cart
<div class="quantity">
<input type="text" name="qty" id="qty" maxlength="12" value="5" class="input-text qty"/>
</div>
</form>
</li>
</ul>
<button type="button" onclick="javascript:checkbox_test()">Add selected to cart</button>
My answer has two parts: Part 1 is a fairly direct answer to your question, and Part 2 is a recommendation for a better way to do this that's maybe more robust and reliable.
Part 1 - Fairly Direct Answer
Instead of a second if to check for the text inputs, you can use a switch, like so:
var boxWasChecked = false;
// loop through all collected objects
for (i = 0; i < input_obj.length; i++) {
// if input object is checkbox and checkbox is checked then ...
switch(input_obj[i].type) {
case 'checkbox':
if (input_obj[i].checked) {
// ... increase counter and concatenate checkbox value to the url string
counter++;
boxWasChecked = true;
url = url + input_obj[i].value + ',qty=';
} else {
boxWasChecked = false;
}
break;
case 'text':
if (boxWasChecked) {
url = url + input_obj[i].value + '|';
boxWasChecked = false;
}
break;
}
}
Here's a fiddle showing it working that way.
Note that I added variable boxWasChecked so you know whether a Qty textbox's corresponding checkbox has been checked.
Also, I wasn't sure exactly how you wanted the final query string formatted, so I set it up as one parameter named product whose value is a pipe- and comma-separated string that you can parse to extract the values. So the url will look like this:
urlcheckout/add?product=321,qty=10|98,qty=5
That seemed better than having a bunch of parameters with the same names, although you can tweak the string building code as you see fit, obviously.
Part 2 - Recommendation for Better Way
All of that isn't a great way to do this, though, as it's highly dependent on the element positions in the DOM, so adding elements or moving them around could break things. A more robust way would be to establish a definitive link between each checkbox and its corresponding Qty textbox--for example, adding an attribute like data-product-id to each Qty textbox and setting its value to the corresponding checkbox's value.
Here's a fiddle showing that more robust way.
You'll see in there that I used getElementsByName() rather than getElementsByTagName(), using the name attributes that you had already included on the inputs:
checkboxes = document.getElementsByName('checked-product'),
qtyBoxes = document.getElementsByName('qty'),
First, I gather the checkboxes and use an object to keep track of which ones have been checked:
var checkedBoxes = {};
// loop through the checkboxes and find the checked ones
for (i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
counter++;
checkedBoxes[checkboxes[i].value] = 1; // update later w/ real qty
}
}
Then I gather the Qty textboxes and, using the value of each one's data-product-id attribute (which I had to add to the markup), determine if its checkbox is checked:
// now get the entered Qtys for each checked box
for (i = 0; i < qtyBoxes.length; i++) {
pid = qtyBoxes[i].getAttribute('data-product-id');
if (checkedBoxes.hasOwnProperty(pid)) {
checkedBoxes[pid] = qtyBoxes[i].value;
}
}
Finally, I build the url using the checkedBoxes object:
// now build our url
Object.keys(checkedBoxes).forEach(function(k) {
url += [
k,
',qty=',
checkedBoxes[k],
'|'
].join('');
});
(Note that this way does not preserve the order of the items, though, so if your query string needs to list the items in the order in which they're displayed on the page, you'll need to use an array rather than an object.)
There are lots of ways to achieve what you're trying to do. Your original way will work, but hopefully this alternative way gives you an idea of how you might be able to achieve it more cleanly and reliably.
Check the below simplified version.
document.querySelector("#submitOrder").addEventListener('click', function(){
var checkStatus = document.querySelectorAll('#basket li'),
urls = [];
Array.prototype.forEach.call(checkStatus, function(item){
var details = item.childNodes,
urlTemplate = '/urlcheckout/add?product=',
url = urlTemplate += details[0].value + '&qty=' + details[1].value;
urls.push(url)
});
console.log(urls);
})
ul{ margin:0; padding:0}
<ul id="basket">
<li class="products"><input type="checkbox" value = "311" name="item"><input type="text"></li>
<li><input type="checkbox" value = "312" name="item"><input type="text"></li>
<li><input type="checkbox" value = "313" name="item"><input type="text"></li>
</ul>
<button id="submitOrder">Submit</button>
I've found various questions similar to what I'm looking to do, but my JS knowledge is almost non-existent so I'm unsure how to code this correctly. I have a few blocks of PHP looping to output my checkboxes like the two below:
<tr>
<td class="first">
P/Hol in lieu
</td>
<?php
for( $x=1; $x<=14; $x++) {
echo '<td class="checkbox checkbox'.$x.'"><input type="checkbox" name="phollieu'.$x.'" id="phollieu'.$x.'" tabindex="'.$x.'"></td>'."\n";
}
?>
</tr>
<tr>
<td class="first">
Public Holiday
</td>
<?php
for( $x=1; $x<=14; $x++) {
echo '<td class="checkbox checkbox'.$x.'"><input type="checkbox" name="phol'.$x.'" id="phol'.$x.'" tabindex="'.$x.'"></td>'."\n";
}
?>
</tr>
What I would like to do is create a JS loop that runs through each group (hence the class checkbox'.$x.' to make sure each column has the same identifier) and only allows one checkbox per group.
I found this code snippet in someone else's question, and when looking at the Fiddle it does exactly what I want it to do, however I'm unsure how to modify the JS to loop. I would use static code but I want to reduce my code as much as possible for readability, and I know I can do it this way.
$('input:checkbox').click( function() {
//If the most recently checked box is in a different group
if($(this).attr('name') != $(this).siblings(':checked').attr('name'))
{
//remove all checks apart from the group that the most recent check has been made
$(this).siblings(':checked').attr('checked', false);
}
});
This is the layout: Screenshot
It seems you want to make checkboxes act like radio buttons, but can't use radios because you want a vertical layout? You can probably make them have a vertical layout using CSS (don't ask me how to to it!), but the following does what you want:
<!-- sample table -->
<table>
<tr>
<td><input type="checkbox" name="col0">
<td><input type="checkbox" name="col1">
<td><input type="checkbox" name="col2">
<tr>
<td><input type="checkbox" name="col0">
<td><input type="checkbox" name="col1">
<td><input type="checkbox" name="col2">
<tr>
<td><input type="checkbox" name="col0">
<td><input type="checkbox" name="col1">
<td><input type="checkbox" name="col2">
</table>
<script>
// Simple function to add click listeners
function addClick() {
var inputs = document.getElementsByTagName('input');
for (var i=0, iLen=inputs.length; i<iLen; i++) {
inputs[i].onclick = checkChecked;
}
}
window.onload = addClick;
// Only allow one checked checkbox per column
function checkChecked() {
var els = document.getElementsByName(this.name);
for (var i=0, iLen=els.length; i<iLen; i++) {
if (els[i] != this) els[i].checked = false;
}
}
</script>
The above is compatible with every browser in use, back to IE 6 or further.
Edit
BTW, if the NodeList interface supported iterators, then the following would be possible:
// Add simple each support in browsers with NodeList constructor
if (typeof NodeList != 'undefined' && NodeList.prototype && !NodeList.prototype.each) {
NodeList.prototype.each = function(fn) {
for (var i=0, iLen=this.length; i<iLen; i++) {
fn(this[i], i, this);
}
}
}
// Simple function to add click listeners
function addClick() {
document.querySelectorAll('input[type=checkbox]').each(function(el){
el.onclick = checkChecked;
});
}
window.onload = addClick;
// Only allow one checked checkbox per column
function checkChecked() {
var tgt = this;
document.querySelectorAll('[name=' + tgt.name + ']').each(function(el) {
if (el != tgt) el.checked = false;
});
}
I'm not suggesting you do the above (altough it works in modern browsers) as it's not robust, particularly for live NodeLists or those modified by the function, but illustrates possibilities. One feature of early libraries was support for selectors, the querySelector interface fixed that.
Now it's time to add an iterator to NodeList that will also be inherited by HTMLCollection… :-)
Here's a simple jQuery function that will do what you need:
function theCheckboxGroups(namePrefix){
$("input:checkbox[name^='"+namePrefix+"']").click(function() {
if($(this).attr('name') != $(this).siblings("[name^='"+namePrefix+"']").attr('name'))
{
$(this).siblings("[name^='"+namePrefix+"']").attr('checked', false);
}
});
}
theCheckboxGroups("phollieu");
theCheckboxGroups("phoy");
The last two lines call the function.
CAVEAT: you will have to rename one of your 'groups', preferably the second one; because they both use 'phol' as a prefix, and so match all your checkbox elements on the page.
EDIT: I misunderstood your question. Please check the updated code below.
function theCheckboxGroups(namePrefix){
$("."+namePrefix).click(function(){
var theID = $(this).attr('class').match(/(\d*$)/)[1];
// Add REGEX to ensure that number is preceded by letters (I'll leave that to you!)
$("input[name$='"+theID+"']").not($(this).children()).attr('checked', false);
});
}
$(".checkbox").each(function(){
theCheckboxGroups($(this).attr('class').split(' ')[1]);
});
It is largely untested, but worked! Also, please make note of the comment in the code (see my comment about the REGEX below).
http://jsfiddle.net/9M9ez/
This is a pretty straightforward question, but I wasn't able to find the answer to it.
Is it possible to do something like this with JavaScript and HTML? So below the names of the checkboxes in order would be 1, 2, 3, 4
<input type="checkbox" name=counter()>
<input type="checkbox" name=counter()>
<input type="checkbox" name=counter()>
<input type="checkbox" name=counter()>
function counter() {
i++;
return i;
}
No, but yes in a different way. Don't include the name attribute (or set the value as ""), and put this code after your checkboxes:
<script type="text/javascript">
var chx = document.getElementsByTagName("input");
for (var i = 0; i < chx.length; i++) {
var cur = chx[i];
if (cur.type === "checkbox") {
cur.name = "checkbox" + i;
}
}
</script>
DEMO: http://jsfiddle.net/bLRLA/
The checkboxes' names will be in the format "checkbox#". This starts counting at 0. If you want to start the names with 1 instead (like you did say), use cur.name = "checkbox" + i + 1;.
Another option for getting the checkboxes is using:
var chx = document.querySelectorAll('input[type="checkbox"]');
With this, you don't have to check the .type inside the for loop.
In either case, it's probably better not to use document, and instead use some more specific container of these elements, so that not all checkboxes are targeted/modified...unless that's exactly what you want.
In the demo, I added extra code so that when you click on the checkbox, it will alert its name, just to prove it's being set properly. That code obviously isn't necessary for what you need....just the code above.
This code could be run immediately after the checkboxes, at the end of the <body>, or in window.onload.
You can get a nodeList of all inputs on the page and then loop through them adding the loop index to whatever the common name string you want for those that have a type of "checkbox". In the following example I have used Array.forEach and Function.call to treat the array like nodeList as an array, to make looping simple.
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
var inputs = document.getElementsByTagName("input");
Array.prototype.forEach.call(inputs, function (input, index) {
if (input.type === "checkbox") {
inputs.name = "box" + index;
}
});
on jsfiddle
Finally, though this has been demonstrated as possible, I think you need to be asking yourself the question "why would I do it this way?". Perhaps there is a better alternative available to you.
Since you're most probably processing the form server-side. you can possibly not bother altering the form markup client-side. For example, simple changing your form markup to the following will do the trick:
<input type="checkbox" value="One" name=counter[]>
<input type="checkbox" value="Two" name=counter[]>
<input type="checkbox" value="Tre" name=counter[]>
<input type="checkbox" value="For" name=counter[]>
Then, for example, using PHP server-side:
<?php
if ( isset( $_REQUEST['counter'] ) ) {
print_r( $_REQUEST['counter'] );
}
?>
I think you're better off creating the elements in code. add a script tag in replace of your controls and use something like this (create a containing div, I've specified one named container in my code below)
for(int i = 0; i < 4; i ++){
var el = document.createElement('input');
el.setAttribute('name', 'chk' + i.toString());
document.getElementById('container').appendChild(el);
}
is there a way to write the same thing clientside using javascript to multiple divs or multiple spots on a page?
I have a php script outputting rows from a database. To edit the contents, I would like to insert a checkbox before each row as with the iphone edit contacts and to do it quickly, I'm trying to use javascript to populate a div with a checkbox before each row using getElemenByID.
One problem is you cannot have more than one div of the same name on a page so I can't write once and have it populate multiple divs of the same name. If I give divs different names than I have to write multiple times which is not appealing especially as the number of rows may vary.
As a related question would checkboxes inserted using javascript even work?
Here is non working code:
js
function edit() }
var box = '<input type="checkbox name=num[]>';
var target = "checkbox";
document.getElementById(target).innerHTML = box;
return;
}//end function
html (generated by PHP from dbase)
<form action="edit.php" method="post">
<a href="javascript:void" onclick="edit()";>edit</a>
<div id="checkbox"></div>Row1 contents<br>
<div id="checkbox"></div>Row2 contents<br>
<form type = "submit" value="Edit">
</form>
Does anyone know a way to do this ie make boxes appear that can then be selected for submission?
Many thanks for any suggestions.
Should be generated using PHP instead, but...
HTML
I'm guessing that you want to use a span element (not a div) for your checkbox placeholder, otherwise you'd have a checkbox on one line, and then "Row1 contents" below the checkbox, versus having the checkbox next to the text.
[X]
Row 1 Contents
versus (span)
[X] Row 1 Contents
<form action="edit.php" method="post" name="frmRows" id="frmRows">
edit
<span class="checkbox"></span>Row1 contents<br>
<span class="checkbox"></span>Row2 contents<br>
<input type = "submit" value="Edit">
</form>
JavaScript
It's not recommended to use .innerHTML in JavaScript unless absolutely necessary (not supported in all browsers, and there are better ways to accomplish the same task.)
function edit() {
var newCb;
var i;
var checkboxList = document.getElementsByClassName( 'checkbox' );
for ( i = 0; i < checkboxList.length; i++ ) {
newCb = document.createElement( 'input' ); // Create a new input element
newCb.setAttribute( 'type', 'checkbox' ); // Set attributes for new element
newCb.setAttribute( 'value', 'SomeValueHere' );
newCb.setAttribute( 'name', 'checkboxName' );
newCb.setAttribute( 'id', 'checkbox-' + i );
checkboxList[i].appendChild( newCB ); // Add checkbox to span.checkbox
}
}
The ID attribute must be unique on each page. You could use the class attribute like this:
<div class="checkbox"></div>Row1 contents<br>
<div class="checkbox"></div>Row2 contents<br>
and then you can use
var check = getElementsByClassName('checkbox');
for (var i=0; i< check.length; i++) {
check[i].innerHTML = box;
}
But... this will not work in IE < 9. If you are using a framework like jQuery they already implemented a workaround for this but with pure JS you have to implement this yourself.
jQuery example
HTML
<div class="checkbox"></div>Row1 contents<br>
<div class="checkbox"></div>Row2 contents<br>
JS
var box = '<input type="checkbox" name="num[]" />';
$(".checkbox").html(box);
The HTML
The first thing to do is to update the generated HTML. In HTML element id attributes should be unique just like field names inside a form. To classify multiple elements as similar you should use the class attribute.
Here is an example of how you could structure the HTML.
<form action="edit.php" method="post">
edit
<div id="row1Identifier" class="editCheckbox"></div>Row1 contents</br>
<div id="row2Identifier" class="editCheckbox"><?div>Row2 contents</br>
<input type="submit" value="Submit">
</form>
The javascript
Using document.getElementsByClassName will return a list of elements with the matching class.
function edit () {
// set up the variables used in this function
var checkboxDivs = document.getElementsByClassName('editCheckbox'),
i,
loopDiv;
// make the change to each div
for (i = 0; i < checkboxDivs.length; i += 1) {
loopDiv = checkboxDivs[i];
loopDiv.innerHTML = '<input type="checkbox" name="' + loopDiv.id + '">';
}
}
Even if you could do it with a single line (using jQuery, for exemplo), you would actually be running a loop through all the divs (that's the only way to change something in various elements: change it in each one).
So you can do this with pure JavaScript using a loop to run the modifications in all the divs, getting them by id (the faster way):
for(var i = 0; i < numberOfDivs; i++){
document.getElementById("myElement" + i).innerHTML = box; //concatenating i to a base id
}
You could also use another slower techniques to get elements by tag name or class, or even use a lib such as jQuery.
If you use jquery:
function edit() {
// box = '<input type="checkbox name=num[]>';
var target = "checkbox";
$(".cb").html(box);
return;
}//end function
<form action="edit.php" method="post">
edit
<div class="cb" id="checkbox">aa</div>Row1 contents<br>
<div class="cb" id="checkbox">bb</div>Row2 contents<br>
</form>