This function limits the number of checkboxes selected by the user, but I'm having trouble getting it to work when the name attribute has square brackets (i.e. name=baz[]).
For some reason I can't get this code to work in jsfiddle, but it's based on this tutorial, which has a working demo.
function chkcontrol(j) {
var total = 0;
for (var i = 0; i < document.form1.baz.length; i++) {
if (document.form1.baz[i].checked) {
total = total + 1;
}
if (total > 3) {
alert("Please select up to three choices")
document.form1.baz[j].checked = false;
return false;
}
}
}
<form name="form1">
<input type=checkbox name="baz[]" value="1" onclick="chkcontrol(0);">Item 1
<input type=checkbox name="baz[]" value="2" onclick="chkcontrol(1);">Item 2
<input type=checkbox name="baz[]" value="3" onclick="chkcontrol(2);">Item 3
<input type=checkbox name="baz[]" value="4" onclick="chkcontrol(3);">Item 4
<input type=checkbox name="baz[]" value="5" onclick="chkcontrol(4);">Item 5
<input type=submit value="submit">
</form>
Chaya, your issue is actually stemming from the fact that "[]" is part of the name.
While there are provisions to turn forms and their named elements into JS-accessible objects automatically, there are no provisions to understand which elements are intended to be arrays, versus non-arrays, as that's a server-side distinction: ?baz[]=1&baz[]=2.
If you were to ask for form1["baz[]"]; you should get a list of all elements named "baz[]".
From there, if you were to say form1["baz[]"][0]; you should get the first element named "baz[]".
You can, of course, write some parsing magic to automatically find all elements with "[]" in their names and append the "baz" as an array of the form, filled with all elements named "baz[]". And at that point you could do exactly what you were looking to do, before.
Whether or not that's overkill depends on what you're doing.
But simply writing form1["baz[]"][i] in your loop shouldn't be much more time-consuming than what you've currently got.
Related
One of our clients' sites has a form that we hijack and submit via AJAX. Recently we got a request to have it support a fluid list of checkboxes with predefined indices in the name - and I'm a little stumped as to how to properly parse this into an array.
Here's an example:
<li><input type="checkbox" name="group[69][4096]" /> Thin</li>
<li><input type="checkbox" name="group[69][8192]" /> Oily</li>
<li><input type="checkbox" name="group[69][16384]" /> Dry</li>
The first- and second-level indices are going to change on a regular basis, so they can't be hard-coded. How can I create a two-dimensional javascript array and place these values under the same keys?
For obvious reasons I don't want to use eval(), and I tried my hand at regex but I'm afraid it isn't my strong suit. I got close - .+\[([0-9]+)\]\[([0-9]+)\] will match the string on http://regexr.com/ - but it doesn't seem to work in js for some reason. At least, I can't get it to return the captured groups.
You could reduce the inputs into a 2d array by parsing each input's name with this regexp /group\[(\d*?)\]\[(\d*?)\]/:
const inputs = Array.from(document.querySelectorAll('[name^="group"]'));
const grid = inputs.reduce((grid, input) => {
const [, y, x] = input.name.match(/group\[(\d*?)\]\[(\d*?)\]/);
grid[y] = grid[y] || [];
grid[y][x] = input.value;
return grid;
}, []);
console.log(grid);
<input name="group[0][0]" value="0,0"/>
<input name="group[0][1]" value="0,1"/>
<input name="group[0][2]" value="0,2"/>
<input name="group[0][3]" value="0,3"/>
<input name="group[0][4]" value="0,4"/>
<input name="group[1][0]" value="1,0"/>
<input name="group[1][1]" value="1,1"/>
<input name="group[1][2]" value="1,2"/>
<input name="group[1][3]" value="1,3"/>
<input name="group[1][4]" value="1,4"/>
<input name="group[2][0]" value="2,0"/>
<input name="group[2][1]" value="2,1"/>
<input name="group[2][2]" value="2,2"/>
<input name="group[2][3]" value="2,3"/>
<input name="group[2][4]" value="2,4"/>
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 have looked all over this site (and Google) for an answer to my problem but I can only seem to find bits and pieces, nothing specific.
I am primarily playing around with JavaScript and HTML but am not trying to use jquery right now.
So, with that said, this is what I'm trying to do: I would like the user to enter two numbers, select an operation (add, subtract, multiply, divide) out of a list of four radio buttons, and then click a button which is linked to a function that does the math and then presents it in a text box on the page. How would I do this using only HTML and JavaScript? I have gotten everything to work up until the point I add the radio buttons.
The code is as follows:
<script>
function operationForm (form) {
var x = document.operationForm.getElementById("numberOne");
var y = document.operationForm.getElementById("numberTwo");
var operation;
var answer;
if (document.operationForm.addSelect.checked === true) {
answer = x + y;
document.operationForm.answerBox.value = answer;
} else if (document.operationForm.subtractSelect.checked === true) {
answer = x - y;
document.operationForm.answerBox.value = answer;
} else if (document.operationForm.multiplySelect.checked === true) {
answer = x * y;
document.operationForm.answerBox.value = answer;
} else(document.operationForm.divideSelect.checked === true) {
answer = x / y;
document.operationForm.answerBox.value = answer;
}
}
</script>
<h1>Let's calculate!</h1>
<form name="operationForm">
<p>
<label>Enter two numbers, select an operation, and then click the button below.
<p>
<label>Number One:
<input type="text" name='numbers' id="numberOne">
<br>
<br>Number Two:
<input type="text" name='numbers' id="numberTwo">
<p>
<input type="radio" name="operations" id="addSelect" value=''>Add
<input type="radio" name="operations" id="subtractSelect" value=''>Subtract
<input type="radio" name="operations" id="multiplySelect" value=''>Multiply
<input type="radio" name="operations" id="divideSelect" value=''>Divide
<label>
<p>
<input type="button" value=" Calculate " onClick='operationForm(form);'>
<p>
<label>Your answer is:
<input type="text" name="answerBox">
If anyone has any fixes or can point me in the right direction of the correct syntax for handling radio buttons, functions linking to them, and onClick events linking to those functions, it would be extremely appreciated.
Consider replacing the <input type="button" value=" Calculate " onClick='operationForm(form);'> with <input type="button" value=" Calculate " onClick='operationForm();'>. Next change the function operationForm to accept no parameters. Then add id to your input answer box. Next for each if statement in the function use the elementById function to get the radios and the answerBox. For example, the first if should be
if (document.getElementById("addSelect").checked) {
answer = x + y;
document.getElementById("answerBox").value = answer;
}
This works:
JavaScript:
<script type="text/javascript">
function operationForm(){
var form = document.forms['operation_form'];
var x = form['numberOne'].value*1;
var y = form['numberTwo'].value*1;
var operation = null;
var answer = null;
if (form['addSelect'].checked == true) {
answer = x + y;
} else if (form['subtractSelect'].checked == true) {
answer = x - y;
} else if (form['multiplySelect'].checked == true) {
answer = x * y;
} else if (form['divideSelect'].checked == true) {
answer = x / y;
}
form['answerBox'].value = answer;
}
</script>
HTML:
<form name="operation_form">
<label>Enter two numbers, select an operation, and then click the button below.</label>
<br/>
<label>Number One:</label><input type="number" name='numberOne' />
<br/>
<br/>Number Two:</label><input type="number" name='numberTwo' />
<br/>
<input type="radio" name="operations" id="addSelect" value='' />Add
<input type="radio" name="operations" id="subtractSelect" value='' />Subtract
<input type="radio" name="operations" id="multiplySelect" value='' />Multiply
<input type="radio" name="operations" id="divideSelect" value='' />Divide
<br/>
<input type="button" value=" Calculate " onclick="operationForm();" />
<br/>
<label>Your answer is:</label><input type="text" name="answerBox">
</form>
Fixes between this and your example:
There are a ton of things wrong with the code you provided. I will update this answer shortly with as many as I can remember.
Update:
Please remember this is meant to be helpful and not punishing. So keep in mind that while listening to the attached feedback, I want you to learn this stuff.
Notes on your HTML:
1.) The biggest problem is none of the <label> elements have closing</label> tags.
Although, none of your html elements have any closing tags.
This will group all of the elements inside one big parent <label>.
So when the browser auto-closes the unclosed tags at the end of the document, this causes a hodgepodge of mixed up child elements. Close your elements.
2.) The first two text boxes have the same name="numbers" attribute. You can only do that with radio type inputs.
3.) Your <form> name="" attribute can NOT have the same name as the JavaScript function you are trying to call. They are stored in the same browser namespace so it causes an error.
Notes on your JavaScript:
1.) Your checked === true is an exact comparison. This will almost never evaluate to be truthful. Use checked == true, or better yet, just use if( my_element.checked ){}. Sometimes .checked will equal a string like this: .checked = 'checked'. So even though 'checked'==true it will never be truthful for 'checked'===true. The === means Exactly Equal. So only true===true.
2.) Your var x = document.opera.. ... .mberOne"); will store the whole <input> element into the x variable. You need to have ...mberOne").value; so just the value of the <input> is stored, not the whole html element.
3.) The only object that has a getElementById() method is the document. You can't use that from a document form object.
4.) You have to convert your x any y input values to numbers. If not, 5 + 5 will give you 55 instead of 10 because they are treated as strings. I multiplied them by * 1 to do that. I also changed the <input type='text' attribute to type='number' just to be safe.
5.) You can assign your answerBox.value just one time at the end of the function instead of doing it once per if(){} bracket. It will work the same but it's just much more readable.
6.) I used the syntax of form['numberOne'] instead of form.numberOne but they both work the same. It is referencing the element name (not necessarily the id) as it exists inside the form. <form> is the only object that lets you do this, whereas a <div> or <p> does not.
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);
}
I have array of checkboxes like below,
<input type="checkbox" value="1" id="a_r_id[1]" name="a_r_id[1]">
<input type="checkbox" value="1" id="a_r_id[2]" name="a_r_id[2]">
<input type="checkbox" value="1" id="a_r_id[3]" name="a_r_id[3]">
<input type="checkbox" value="1" id="a_r_id[4]" name="a_r_id[4]">
in my page... and i want to submit only the checked one via JavaScript (jQuery AJAX)... how can i do that ?
EDITED :
Actually, i want to get all array keys on the checked checkbox so that i can post it via ajax. Something like "1,4" as a string.
var keys = [],
keystring;
$('input[name^="a_r_id"]:checked').each(function () {
keys.push($(this).attr('name').replace(/a_r_id\[(\d+)\]/, '$1'));
});
keystring = keys.join();
Of course, there are better ways of doing this, but this answers your question as you've framed it.
Finally, i found an answer for my question above. I'll write it down right here.
Problem :
how can i get "key" from array HTML element(s) ? (in my case, only checked checkbox i want to get)
my answer code is something like this :
//first, i get every checked checkbox using jQuery selector,
//as mentioned by DerekHenderson.
var list_agent = $('input[name^="a_r_id"]:checked');
var l_c_agent = new Array();
//then, i create a loop to loop each object returned.
for(var i=0;i<list_agent.length;i++){
//after that, i'm using Regular Expression ( match() ) on every returned object id and throw it into some array.
l_c_agent[i] = list_agent[i].id.match(/[0-9]+/);
}
//finally, i join the array using javascript join() method so that i can pass it using jQuery AJAX as a string to my controller and process it.
var clean_agent_list = l_c_agent.join();
var add_url = 'test.php';
$.ajax({
url: add_url,
type: "GET",
data : { 'list_agent' : clean_agent_list },
success: function(data_return) {
//alert(data_return);
}
});
the output will be something like this (if using my example question above and we're check element with id 1,3 and 4 only)
1,3,4
if anybody have a better code, please write it here so that we can discuss which is better to solve my problem.
The method you want seems a bit backwards; the browser will already submit only the checked checkboxes, but here goes:
var re = /\[(\d+)\]$/,
numbers = [];
$('input[name^="a_r_id\\["]:checked').each(function() {
numbers.push(+this.name.match(re)[1]);
});
console.log(numbers.join(','));
It selects all checked boxes whose name starts with "a_r_id[". Then, a regular expression is used to extract the number portion between square brackets and added to the list of values.
I think you want to do something like this
<input type="checkbox" value="1" id="a_r_id_1" name="a_r_id[]">
<input type="checkbox" value="2" id="a_r_id_2" name="a_r_id[]">
<input type="checkbox" value="3" id="a_r_id_3" name="a_r_id[]">
<input type="checkbox" value="4" id="a_r_id_4" name="a_r_id[]">
Radio Buttons seems to be more applicable here rather than checkboxes try this:
<input type="radio" name="radiogroup" value="1" id="a_r_id[1]" name="a_r_id[1]">
<input type="radio" name="radiogroup" value="2" id="a_r_id[2]" name="a_r_id[2]">
<input type="radio" name="radiogroup" value="3" id="a_r_id[3]" name="a_r_id[3]">
You can get the selected value using
$("input:radio[name=radiogroup]").click(function() {
var value = $(this).val();
//
do something with var
//
});