How to overcome undefined error in javascript - javascript

Here is my code. You can also find it at a jsfiddle.
<form name="myform" method="post" onsubmit="return arith()">
<center><table>
<tr><td><font face="verdana,arial" size=-1>Value 1 </font></td><td><input type = "text" id = "num1"></td></tr>
<tr><td><font face="verdana,arial" size=-1>Value 2 </font></td><td><input type = "text" id = "num2"></td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Addition" id="check1"/>Addition</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Subtraction" id="check2"/>Subtraction</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Multiplication" id="check3"/>Multiplication</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Division" id="check4"/>Division</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><font face="verdana,arial" size=-1><input type = "submit" value = "Submit"></font></td></tr>
</table></center>
</form>
<p id="demo"></p>
Javascript code:
<script>
var op;
function changeCheckBox(val) {
try {
var i;
var max = document.myform.check.length;
var count = 0;
op = val;
for (i = 0; i < max; i++) {
if (document.myform.check[i].checked === true) {
count++;
serNoChecked = i;
}
}
if (count === 1) {
for (i = 0; i < max; i++) {
if (document.myform.check[i].checked === false) {
document.myform.check[i].disabled = true;
}
}
} else if (count === 0) {
for (i = 0; i < max; i++) {
document.myform.check[i].disabled = false;
}
}
if (null === max) return false;
if (count === 0) {
return true;
} else if (count > 0) {
return false;
}
} catch (e) {
alert(e.message);
}
}
function arith() {
var n1 = parseInt(document.getElementById('num1').value, 10);
var n2 = parseInt(document.getElementById('num2').value, 10);
var newVal1;
var newVal2;
var newVal3;
var newVal4;
if (op == "Addition") {
newVal1 = n1 + n2;
} else if (op == "Subtraction") {
newVal2 = n1 - n2;
} else if (op == "Multiplication") {
newVal3 = n1 * n2;
} else if (op == "Division") {
newVal4 = n1 / n2;
}
var demoP = document.getElementById("demo");
{
var html = "";
html += "Addition =" + newVal1 + "<br/>";
html += "Subtraction =" + newVal2 + "<br/>";
html += "Multiplication =" + newVal3 + "<br/>";
html += "Division =" + newVal4 + "<br/>";
demoP.innerHTML = html;
}
return false;
}
</script>
While running it, I am getting undefined error for all the four operations.
If the user enters the two values and if they click all the checkboxes, it should display all the outputs corresponding to the arithmetic operations. How to do that?

You're not calling changeCheckBox anywhere in your code thus, the op is never set. Maybe you meant to have onchange="changeCheckBox(this.value);" for every check box (with this change, your code seems to be working as expected)?
<form name="myform" method="post" onsubmit="return arith()">
<center><table>
<tr><td><font face="verdana,arial" size=-1>Value 1 </font></td><td><input type = "text" id = "num1"></td></tr>
<tr><td><font face="verdana,arial" size=-1>Value 2 </font></td><td><input type = "text" id = "num2"></td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Addition" id="check1" onchange="changeCheckBox(this.value);" />Addition</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Subtraction" id="check2" onchange="changeCheckBox(this.value);" />Subtraction</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Multiplication" id="check3" onchange="changeCheckBox(this.value);" />Multiplication</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><input type="checkbox" name="check" value="Division" id="check4" onchange="changeCheckBox(this.value);" />Division</td></tr>
<tr><td><font face="verdana,arial" size=-1></font></td><td><font face="verdana,arial" size=-1><input type = "submit" value = "Submit"></font></td></tr>
</table></center>
</form>
Hope this helps.

Related

My JavaScript isn't responding to my HTML and CSS properly (namely buttons and <form> tags)

I am currently working on a donate page for a site that I'm working on in my free time. It's been going smoothly up until last week when I encountered a problem. My JS isn't responding properly to my HTML and I can't fix it. Here's my HTML:
var donateAmount = document.getElementById("selectedAmount");
if (donateAmount.value == "amount0") {
var totalAmount = 0;
} else if (donateAmount.value == "amount1") {
var totalAmount = 10;
} else if (donateAmount.value == "amount2") {
var totalAmount = 50;
} else if (donateAmount.value == "amount3") {
var totalAmount = 100;
} else if (donateAmount.value == "amount4") {
var totalAmount = 500;
};
function donateIsPressed() {
if (totalAmount >= = 0) {
alert("Thank you for your donation of " + totalAmount "$!")
} else {
alert("You didn't select anything!")
};
};
<form id="selectedAmount" name="selectedAmount">
<input type="radio" name="donateRadio" value="amount0"> 0 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount1"> 10 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount2"> 50 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount3"> 100 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount4"> 500 Dollars </input>
</form>
<div onclick='donateIsPressed ();' class="donateButton" id="processDonation"> test donate button </div>
The HTML is pretty simple, there's a tag with multiple options, and a button that's supposed to start the transaction. What the JS is supposed to do is to check what option is selected, then set the "totalAmount" variable to whatever is selected. Then it's supposed to give an answer depending on what totalAmount's value is. However, none of it works, and I'm currently getting nowhere with fixing. So I would appreciate it if one of you guys could point me in the right direction
Thanks in advance.
Try this.
function donateIsPressed() {
var donateAmount = document.querySelector('input[name="donateRadio"]:checked');
if (donateAmount) {
if (donateAmount.value == "amount0") {
var totalAmount = 0;
} else if (donateAmount.value == "amount1") {
var totalAmount = 10;
} else if (donateAmount.value == "amount2") {
var totalAmount = 50;
} else if (donateAmount.value == "amount3") {
var totalAmount = 100;
} else if (donateAmount.value == "amount4") {
var totalAmount = 500;
};
}
if (totalAmount >= 0) {
alert("Thank you for your donation of " + totalAmount + "$!")
} else {
alert("You didn't select anything!")
};
};
<form id="selectedAmount" name="selectedAmount">
<input type="radio" name="donateRadio" value="amount0"> 0 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount1"> 10 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount2"> 50 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount3"> 100 Dollars </input> <br>
<input type="radio" name="donateRadio" value="amount4"> 500 Dollars </input>
</form>
<div onclick='donateIsPressed ();' class="donateButton" id="processDonation"> test donate button </div>
I tried to solve your problem :
First I changed buttons value
Then I implement this logic :
var donateAmount = document.getElementById("selectedAmount");
var totalAmount = -1
function donateIsPressed() {
var radios = donateAmount.elements["donateRadio"];
for (var i = 0; i < radios.length; i++) {
if (radios[i].checked) { // radio checked?
totalAmount = parseInt(radios[i].value); // if so, hold its value in val
break; // and break out of for loop
}
}
if (totalAmount >= 0) {
alert("Thank you for your donation of " + totalAmount + "$!")
} else {
alert("You didn't select anything!")
};
};
<form id="selectedAmount" name="selectedAmount">
<input type="radio" name="donateRadio" value="0"> 0 Dollars </input> <br>
<input type="radio" name="donateRadio" value="10"> 10 Dollars </input> <br>
<input type="radio" name="donateRadio" value="50"> 50 Dollars </input> <br>
<input type="radio" name="donateRadio" value="100"> 100 Dollars </input> <br>
<input type="radio" name="donateRadio" value="500"> 500 Dollars </input>
<div onclick='donateIsPressed ();' class="donateButton" id="processDonation"> test donate button </div>
</form>
//Globals
let procesDonation, selectedAmount;
const data = {amount0: 0, amount1: 10, amount2: 50, amount3: 100, amount4: 500};
//Setup
const setup = () => {
//Id's should be unique and so can be set gobal
processDonation = document.querySelector('#processDonation');
selectedAmount = document.querySelector('#selectedAmount');
processDonation.addEventListener('click', donateOnClick);
};
//Functions
const donateOnClick = (event) => {
if(selectedAmount == null) return;
const target = event.currentTarget;
if(target.nodeName == 'DIV') {
const selectedButton = selectedAmount.querySelector('[name="donateRadio"]:checked');
const key = selectedButton?.value;
const amount = getAmount(key);
donateMessage(amount);
}
};
const getAmount = (key) => {
if(data == null || key == null || !Object.keys(data).includes(key)) return;
return data[key] || 0;
}
const donateMessage = (amount) => {
if(amount == null) return;
const message = amount > 0 ? `Thank you for your donation of ${amount}$!"` : `You didn't select anything!`;
alert(message);
}
window.addEventListener('load', setup);
<form id="selectedAmount" name="selectedAmount">
<input type="radio" name="donateRadio" value="amount0" checked> <label>0 Dollars</label> <br>
<input type="radio" name="donateRadio" value="amount1"> <label>10 Dollars</label> <br>
<input type="radio" name="donateRadio" value="amount2"> <label>50 Dollars</label> <br>
<input type="radio" name="donateRadio" value="amount3"> <label>100 Dollars</label> <br>
<input type="radio" name="donateRadio" value="amount4"> <label>500 Dollars</label>
</form>
<div class="donateButton" id="processDonation"> test donate button </div>
var totalAmount = 0;
var donateAmount = document.getElementById("selectedAmount");
function donateIsPressed() {
if (donateAmount.value == "amount1") {
var totalAmount = 10;
} else if (donateAmount.value == "amount2") {
var totalAmount = 50;
} else if (donateAmount.value == "amount3") {
var totalAmount = 100;
} else if (donateAmount.value == "amount4") {
var totalAmount = 500;
};
if (totalAmount >= 0) { // extra = here, removed
alert("Thank you for your donation of " + totalAmount "$!")
} else {
alert("You didn't select anything!")
};
};

Javascript code returning "Not found" when script is called

Updated with entire code for context
My code should run the function when the calculate button is pressed ( in this case, I was testing to see if it would display the alert if I check no radio buttons) but instead the page returns "Not found" message.
Now, I'm totally new at this so it's gone over my head as to what is wrong.
Bonus question: Could I have a hint as to how I make my function look at which buttons are selected and make a calculation from that? Example: If I wanted to selected radio button 1 (having a value of 10) and 3 (having a value of 4) the function would add them together to make 14, and so on for whichever choices you select.
function calculation() {
var cost = 0; //Base cost of flight (one way Economy)
var radioButton; // A radio button
var selection = 0; // The selected radio button, 1 to 6 going down.
for (var i = 1; i <= 6; i++) { // Get the number of the selection (1 to 6)
radioButton = document.getElementById("destination" + i);
if (radioButton.checked == true) {
selection = i;
}
// Give Base cost of flight
if (selection == 1) {
cost = 229
} else if (selection == 2) {
cost = 259
} else if (selection == 3) {
cost = 199
} else if (selection == 4) {
cost = 179
} else if (selection == 5) {
cost = 179
} else if (selection == 6) {
cost = 239
}
// Check if a flight was not selected and prompt
else if (selection == 0) {
alert("Please select a flight.");
}
seating = 0;
for (var x = 1; x <= 3; x++) {
radioButton = document.getElementById("seating" + x);
if (radioButton.checked == true) {
seating = radioButton.id;
}
}
}
}
<h1> Hawkins Airlines Fare Calculator</h1>
<p> Complete the form below to calculate the cost of your flight.</p>
<form>
<p>Route:</p>
<input type="radio" id="destination1"> Hawkins - Riverdale<br>
<input type="radio" id="destination2"> Hawkins - Haddonfield<br>
<input type="radio" id="destination3"> Hawkins - Rockwell<br>
<input type="radio" id="destination4"> Hawkins - Eagleton<br>
<input type="radio" id="destination5"> Hawkins - Pawnee<br>
<input type="radio" id="destination6"> Hawkins - Twin Peaks<br>
<br>
<input type="checkbox" name="appliances" id="return">
<label>Click here if you will be purchasing a return fare </label><br>
<p>Seating class:</p>
<input type="radio" id="seating1"> First seating<br>
<input type="radio" id="seating2"> Business seating<br>
<input type="radio" id="seating3"> Economy seating<br>
<br>
<button onclick="calculation()"> Calculate </button>
<input type="reset" value="Restore Defults">
</form>
I just fixed the javascript code. You should not use class as a variable and there was a missing {} in your first loop
<!DOCTYPE html>
<html>
<head>
</head>
<script>
function calculation() {
var cost = 0; //Base cost of flight (one way Economy)
var radioButton; // A radio button
var selection = 0; // The selected radio button, 1 to 6 going down.
for (var i = 1; i <= 6; i++) {// Get the number of the selection (1 to 6)
radioButton = document.getElementById("destination" + i);
if (radioButton.checked == true) {
selection = i;
}
}
if (selection == 1) {
cost = 229
} else if (selection == 2) {
cost = 259
} else if (selection == 3) {
cost = 199
} else if (selection == 4) {
cost = 179
} else if (selection == 5) {
cost = 179
} else if (selection == 6) {
cost = 239
} else if (selection == 0) {
alert("Please select a flight.");
return false;
}
var seating = 0;
for (var x = 1; x <= 3; x++) {
radioButton = document.getElementById("seating" + x);
if (radioButton.checked == true) {
seating = x;
}
}
var totalcost = 0;
if(seating == 0){
alert("Please select a seat.");
return false;
} else if(seating == 1){
totalcost = cost + (cost * 2);
} else if(seating == 2){
totalcost = cost + (cost * 1.5);
} else if(seating == 3){
totalcost = cost;
}
if(document.getElementById("return").checked){
totalcost = totalcost*2;
}
totalcost = totalcost + cost;
alert("Total cost: "+totalcost);
}
</script>
<body>
<h1> Hawkins Airlines Fare Calculator</h1>
<p> Complete the form below to calculate the cost of your flight.</p>
<form onsubmit="return false;">
<p>Route:</p>
<input type="radio" name="destination" id="destination1"> Hawkins - Riverdale<br>
<input type="radio" name="destination" id="destination2"> Hawkins - Haddonfield<br>
<input type="radio" name="destination" id="destination3"> Hawkins - Rockwell<br>
<input type="radio" name="destination" id="destination4"> Hawkins - Eagleton<br>
<input type="radio" name="destination" id="destination5"> Hawkins - Pawnee<br>
<input type="radio" name="destination" id="destination6"> Hawkins - Twin Peaks<br>
<br>
<input type="checkbox" name="appliances" id="return">
<label>Click here if you will be purchasing a return fare </label><br>
<p>Seating class:</p>
<input type="radio" name="seating" id="seating1"> First seating<br>
<input type="radio" name="seating" id="seating2"> Business seating<br>
<input type="radio" name="seating" id="seating3"> Economy seating<br>
<br>
<button onclick="calculation()"> Calculate </button>
<input type="reset" value="Restore Defults">
</form>
</body>
</html>

jquery if checked all sum x2

I have some problem with sum
example:
if checkbox with id='sms' is checked total sum x2 else x1
<form>
<input onclick="clickCh(this)" type="checkbox" value="1.00"> $1.00<br>
<input onclick="clickCh(this)" type="checkbox" value="2.00"> $2.00<br>
<input id="sms" type="checkbox"> pay via sms<br>
<BR>
<input id="total" type="text" name="total">
</form>
</div>
<script>
var total = document.getElementById("total")
$('#sms').change(function(){
var rise = this.checked ? '2' : '1';
});
function clickCh(caller){
if(caller.checked){
add(caller)
} else {
subtract(caller)
}
}
function add(caller){
total.value = total.value*1 + caller.value*1 * rise
}
function subtract(caller){
total.value = total.value*1 - caller.value*1 * rise
}
</script>
rise's scope is only within this function:
$('#sms').change(function(){
var rise = this.checked ? '2' : '1';
});
Declare it outside then modify it:
var rise;
$('#sms').change(function(){
rise = this.checked ? 2 : 1;
});

checked checkbox to enable text field with validation

I have a Paypal form which has been built using some borrowed code. The main purpose of the form is to add some optional extras to a standard product and send that data to the paypal checkout. It seems to be working quite well, but...
I have a text field that I want to be required when the related checkbox is checked and for it to be disabled, and therefore not required when its unchecked.
Crucially I need the data in the text field to be sent to the paypal shopping basket.
I have validation on another text field which will always be required, that works and sends the data to Paypal, but I'm a javascript newbie and can't get to grips with the second field.
This is the borrowed javascript
function Dollar (val) { // force to valid dollar amount
var str,pos,rnd=0;
if (val < .995) rnd = 1; // for old Netscape browsers
str = escape (val*1.0 + 0.005001 + rnd); // float, round, escape
pos = str.indexOf (".");
if (pos > 0) str = str.substring (rnd, pos + 3);
return str;
}
var amt,des,obj,val,op1a,op1b,op2a,op2b,itmn;
function ChkTok (obj1) {
var j,tok,ary=new Array (); // where we parse
ary = val.split (" "); // break apart
for (j=0; j<ary.length; j++) { // look at all items
// first we do single character tokens...
if (ary[j].length < 2) continue;
tok = ary[j].substring (0,1); // first character
val = ary[j].substring (1); // get data
if (tok == "#") amt = val * 1.0;
if (tok == "+") amt = amt + val*1.0;
if (tok == "%") amt = amt + (amt * val/100.0);
if (tok == "#") { // record item number
if (obj1.item_number) obj1.item_number.value = val;
ary[j] = ""; // zap this array element
}
// Now we do 3-character tokens...
if (ary[j].length < 4) continue;
tok = ary[j].substring (0,3); // first 3 chars
val = ary[j].substring (3); // get data
if (tok == "s1=") { // value for shipping
if (obj1.shipping) obj1.shipping.value = val;
ary[j] = ""; // clear it out
}
if (tok == "s2=") { // value for shipping2
if (obj1.shipping2) obj1.shipping2.value = val;
ary[j] = ""; // clear it out
}
}
val = ary.join (" "); // rebuild val with what's left
}
function StorVal () {
var tag;
tag = obj.name.substring (obj.name.length-2); // get flag
if (tag == "1a") op1a = op1a + " " + val;
else if (tag == "1b") op1b = op1b + " " + val;
else if (tag == "2a") op2a = op2a + " " + val;
else if (tag == "2b") op2b = op2b + " " + val;
else if (tag == "3i") itmn = itmn + " " + val;
else if (des.length == 0) des = val;
else des = des + ", " + val;
}
function ReadForm (obj1, tst) { // Read the user form
var i,j,pos;
amt=0;des="";op1a="";op1b="";op2a="";op2b="";itmn="";
if (obj1.baseamt) amt = obj1.baseamt.value*1.0; // base amount
if (obj1.basedes) des = obj1.basedes.value; // base description
if (obj1.baseon0) op1a = obj1.baseon0.value; // base options
if (obj1.baseos0) op1b = obj1.baseos0.value;
if (obj1.baseon1) op2a = obj1.baseon1.value;
if (obj1.baseos1) op2b = obj1.baseos1.value;
if (obj1.baseitn) itmn = obj1.baseitn.value;
for (i=0; i<obj1.length; i++) { // run entire form
obj = obj1.elements[i]; // a form element
if (obj.type == "select-one") { // just selects
if (obj.name == "quantity" ||
obj.name == "amount") continue;
pos = obj.selectedIndex; // which option selected
val = obj.options[pos].value; // selected value
ChkTok (obj1); // check for any specials
if (obj.name == "on0" || // let this go where it wants
obj.name == "os0" ||
obj.name == "on1" ||
obj.name == "os1") continue;
StorVal ();
} else
if (obj.type == "checkbox" || // just get checkboxex
obj.type == "radio") { // and radios
if (obj.checked) {
val = obj.value; // the value of the selection
ChkTok (obj1);
StorVal ();
}
} else
if (obj.type == "select-multiple") { //one or more
for (j=0; j<obj.options.length; j++) { // run all options
if (obj.options[j].selected) {
val = obj.options[j].value; // selected value (default)
ChkTok (obj1);
StorVal ();
}
}
} else
if (obj.name == "size") {
val = obj.value; // get the data
if (val == "" && tst) { // force an entry
alert ("Enter data for " + obj.name);
return false;
}
StorVal ();
} else
if (obj.name == "stamp") {
val = obj.value; // get the data
//if (val == "" && tst) { // force an entry
// alert ("Enter data for " + obj.name);
// return false;
//}
StorVal ();
}
}
// Now summarize stuff we just processed, above
if (op1a.length > 0) obj1.on0.value = op1a;
if (op1b.length > 0) obj1.os0.value = op1b;
if (op2a.length > 0) obj1.on1.value = op2a;
if (op2b.length > 0) obj1.os1.value = op2b;
if (itmn.length > 0) obj1.item_number.value = itmn;
obj1.item_name.value = des;
obj1.amount.value = Dollar (amt);
if (obj1.tot) obj1.tot.value = "£" + Dollar (amt);
}
and this is the html
<form action="https://www.paypal.com/cgi-bin/webscr" name="weboptions" method="post" onsubmit="this.target='_blank'; return ReadForm(this, true);">
<input type="hidden" name="cmd" value="_cart" />
<input type="hidden" name="add" value="1" />
<input type="hidden" name="business" value="craig#craigomatic.co.uk" />
<input type="hidden" name="shipping" value="0.00">
<input type="hidden" name="no_shipping" value="1">
<input type="hidden" name="return" value="">
<input type="hidden" name="item_name" value />
<input type="hidden" name="amount" value />
<input type="hidden" name="currency_code" value="GBP" />
<input type="hidden" name="lc" value="US" />
<input type="hidden" name="bn" value="PP-ShopCartBF">
<input type="hidden" name="basedes" value="Collar">
<h4>Collar details...</h4>
<div>
<p>Matching lamb nappa lining <br />
with antique brass finished hardware</p>
<div>
<p>Pick a colour:</p>
<p>Chose a width:</p>
<p>Tell us the Size:<br />
in cms (?)</p>
</div>
<div>
<p>
<select name="colour" onclick="ReadForm (this.form, false);" size="1">
<option value="Black +55.00">Black</option>
<option value="Brown +55.00">Brown</option>
<option value="Tan +55.00">Tan</option>
</select>
</p>
<p>
<select name="width" onclick="ReadForm (this.form, false);" size="1">
<option value="1 and quarter inch">1¼ inch</option>
<option value="1 and half inch">1½ inch</option>
</select>
</p>
<p><input name="size" type="text" class="size"></p>
<p></p>
</div>
</div>
<h4>Optional extras...</h4>
<div>
<p>
<label>
<input type ="checkbox" onclick="ReadForm (this.form, false);"
value ="Double D +1.50"
name ="DoubleD">
Double D Me (£1.50)
</label>
</p>
<p>
<label>
<input type ="checkbox" onclick="ReadForm (this.form, false);"
value ="Max Me +1.50"
name ="MaxMe">
Max Me! (£1.50)
</label>
</p>
<p>
<label>
<input type ="checkbox" onclick="ReadForm (this.form, false);"
value ="Match Me +1.50"
name ="MatchMe">
Match Me (£1.50)
</label>
</p>
<p>
<label>
<input type ="checkbox" onclick="ReadForm (this.form, false);"
value ="Stamp Me +1.50"
name ="StampMe">
Stamp Me (£1.50)</label>
</p>
<p><input name="stamp" type="text" class="lettering" maxlength="12"></p>
</div>
<p>Total:<input class="nbor" type="text" name="tot" size="7" value="£55.00" /> <input class="buy" type="submit" value="Buy Me" name="B1"></p>
</form>
If your wondering you can find the page in question here http://booleather.co.uk/option1/bronze-bronco.php
Any help would be much appreciated.
Give this code a try:
if (val == "" && obj1.elements["StampMe"].checked) {
// if the value of the stamp text field is empty and the user has checked the StampMe box
alert ("Enter data for " + obj.name);
return false;
}
(instead of)
//if (val == "" && tst) { // force an entry
// alert ("Enter data for " + obj.name);
// return false;
//}

How can I shift-select multiple checkboxes like GMail?

In GMail, the user can click on one checkbox in the email list, hold down the Shift key, and select a second checkbox. The JavaScript will then select/unselect the checkboxes that are between the two checboxes.
I am curious as to how this is done? Is this JQuery or some basic (or complex) JavaScript?
I wrote a self-contained demo that uses jquery:
$(document).ready(function() {
var $chkboxes = $('.chkbox');
var lastChecked = null;
$chkboxes.click(function(e) {
if (!lastChecked) {
lastChecked = this;
return;
}
if (e.shiftKey) {
var start = $chkboxes.index(this);
var end = $chkboxes.index(lastChecked);
$chkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', lastChecked.checked);
}
lastChecked = this;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
</head>
<body>
<input type="checkbox" id="id_chk1" class="chkbox" value="1" />Check 1<br/>
<input type="checkbox" id="id_chk2" class="chkbox" value="2" />Check 2<br/>
<input type="checkbox" id="id_chk3" class="chkbox" value="3" />Check 3<br/>
<input type="checkbox" id="id_chk4" class="chkbox" value="4" />Check 4<br/>
<input type="checkbox" id="id_chk5" class="chkbox" value="5" />Check 5<br/>
<input type="checkbox" id="id_chk6" class="chkbox" value="6" />Check 6<br/>
<input type="checkbox" id="id_chk7" class="chkbox" value="7" />Check 7<br/>
</body>
</html>
This is done through fairly simple javascript.
They keep track of the id of the last checked box and when when another checkbox is checked they use the shiftKey event attribute to see if shift was held while clicking the checkbox. If so they set the checked property of each checkbox in between the two to true.
To determine when a box is checked they probably use an onclick event on the checkboxes
It seems like every answer I can find online is completely dependent on jQuery for this. JQuery adds very little functionality. Here's a quick version that doesn't require any frameworks:
function allow_group_select_checkboxes(checkbox_wrapper_id){
var lastChecked = null;
var checkboxes = document.querySelectorAll('#'+checkbox_wrapper_id+' input[type="checkbox"]');
//I'm attaching an index attribute because it's easy, but you could do this other ways...
for (var i=0;i<checkboxes.length;i++){
checkboxes[i].setAttribute('data-index',i);
}
for (var i=0;i<checkboxes.length;i++){
checkboxes[i].addEventListener("click",function(e){
if(lastChecked && e.shiftKey) {
var i = parseInt(lastChecked.getAttribute('data-index'));
var j = parseInt(this.getAttribute('data-index'));
var check_or_uncheck = this.checked;
var low = i; var high=j;
if (i>j){
var low = j; var high=i;
}
for(var c=0;c<checkboxes.length;c++){
if (low <= c && c <=high){
checkboxes[c].checked = check_or_uncheck;
}
}
}
lastChecked = this;
});
}
}
And then initialize it whenever you need it:
allow_group_select_checkboxes('[id of a wrapper that contains the checkboxes]')
Recently, I wrote a jQuery plugin that provide that feature and more.
After including the plugin you just need to initialize the context of checkboxes with the following code snippet:
$('#table4').checkboxes({ range: true });
Here is the link to the documentation, demo & download: http://rmariuzzo.github.io/checkboxes.js/
Well, the post is quite old but here is a solution I've just come across:
jQuery Field Plug-In
I took the jQuery version from #BC. and transformed it into an ES6 version, since the code is actually pretty elegantly solving the problem, in case anyone still stumbles across this...
function enableGroupSelection( selector ) {
let lastChecked = null;
const checkboxes = Array.from( document.querySelectorAll( selector ) );
checkboxes.forEach( checkbox => checkbox.addEventListener( 'click', event => {
if ( !lastChecked ) {
lastChecked = checkbox;
return;
}
if ( event.shiftKey ) {
const start = checkboxes.indexOf( checkbox );
const end = checkboxes.indexOf( lastChecked );
checkboxes
.slice( Math.min( start, end ), Math.max( start, end ) + 1 )
.forEach( checkbox => checkbox.checked = lastChecked.checked );
}
lastChecked = checkbox;
} ) );
}
Got this solution from http://abcoder.com/javascript/jquery/simple-check-uncheck-all-jquery-function/ (now dead):
JavaScript and HTML code
var NUM_BOXES = 10;
// last checkbox the user clicked
var last = -1;
function check(event) {
// in IE, the event object is a property of the window object
// in Mozilla, event object is passed to event handlers as a parameter
if (!event) { event = window.event }
var num = parseInt(/box\[(\d+)\]/.exec(this.name)[1]);
if (event.shiftKey && last != -1) {
var di = num > last ? 1 : -1;
for (var i = last; i != num; i += di) {
document.forms.boxes['box[' + i + ']'].checked = true;
}
}
last = num;
}
function init() {
for (var i = 0; i < NUM_BOXES; i++) {
document.forms.boxes['box[' + i + ']'].onclick = check;
}
}
<body onload="init()">
<form name="boxes">
<input name="box[0]" type="checkbox">
<input name="box[1]" type="checkbox">
<input name="box[2]" type="checkbox">
<input name="box[3]" type="checkbox">
<input name="box[4]" type="checkbox">
<input name="box[5]" type="checkbox">
<input name="box[6]" type="checkbox">
<input name="box[7]" type="checkbox">
<input name="box[8]" type="checkbox">
<input name="box[9]" type="checkbox">
</form>
</body>
Inspired by the fine answers provided, here's a plain JavaScript version using Array.prototype to coerce nodelists to use array functions, rather than for loops.
(function () { // encapsulating variables with IIFE
var lastcheck = null // no checkboxes clicked yet
// get desired checkboxes
var checkboxes = document.querySelectorAll('div.itemslist input[type=checkbox]')
// loop over checkboxes to add event listener
Array.prototype.forEach.call(checkboxes, function (cbx, idx) {
cbx.addEventListener('click', function (evt) {
// test for shift key, not first checkbox, and not same checkbox
if ( evt.shiftKey && null !== lastcheck && idx !== lastcheck ) {
// get range of checks between last-checkbox and shift-checkbox
// Math.min/max does our sorting for us
Array.prototype.slice.call(checkboxes, Math.min(lastcheck, idx), Math.max(lastcheck, idx))
// and loop over each
.forEach(function (ccbx) {
ccbx.checked = true
})
}
lastcheck = idx // set this checkbox as last-checked for later
})
})
}())
<div class="itemslist">
<input type="checkbox" name="one" value="1">
<input type="checkbox" name="two" value="2">
<input type="checkbox" name="three" value="3">
<input type="checkbox" name="four" value="4">
<input type="checkbox" name="five" value="5">
</div>
I realy liked gyo's example and added some code so it works on all checkboxes with the same name.
I also added a MutationObserver so events are also handled on newly added checkboxes.
$(document).ready(function() {
var previouslyClicked = {};
var rangeEventHandler = function(event) {
if (event.shiftKey && previouslyClicked[this.name] && this != previouslyClicked[this.name]) {
var $checkboxes = $('input[type=checkbox][name='+this.name+']').filter(':visible');
var start = $checkboxes.index( this );
var end = $checkboxes.index( previouslyClicked[this.name] );
// console.log('range', start, end, this, previouslyClicked[this.name]);
$checkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', previouslyClicked[this.name].checked);
} else {
previouslyClicked[this.name] = this;
}
};
if ("MutationObserver" in window) { // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/MutationObserver to refresh on new checkboxes
var mutationCallback = function(mutationList, observer) {
mutationList.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeName == 'INPUT' && node.type == 'checkbox') {
$(node).on('click.selectRange', rangeEventHandler);
}
});
});
};
var observer = new MutationObserver(mutationCallback);
observer.observe(document, {
childList: true,
attributes: false, // since name is dynamically read
subtree: true
});
}
$('input[type=checkbox][name]').on('click.selectRange', rangeEventHandler);
});
<html>
<head>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
First:
<input type="checkbox" name="first">
<input type="checkbox" name="first">
<input type="checkbox" name="first">
<input type="checkbox" name="first">
<input type="checkbox" name="first">
</div>
<div>
Second:
<input type="checkbox" name="second">
<input type="checkbox" name="second">
<input type="checkbox" name="second">
<input type="checkbox" name="second">
<input type="checkbox" name="second">
</div>
</body>
</html>
Found the better solution it works for both select and deselects checkboxes.
Uses a core javascript & Jquery.
$(document).ready(function() {
var $chkboxes = $('.chkbox');
var lastChecked = null;
$chkboxes.click(function(e) {
if(!lastChecked) {
lastChecked = this;
return;
}
if(e.shiftKey) {
var start = $chkboxes.index(this);
var end = $chkboxes.index(lastChecked);
$chkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', e.target.checked);
}
lastChecked = this;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
</head>
<body>
<input type="checkbox" id="id_chk1" class="chkbox" value="1" />Check 1<br/>
<input type="checkbox" id="id_chk2" class="chkbox" value="2" />Check 2<br/>
<input type="checkbox" id="id_chk3" class="chkbox" value="3" />Check 3<br/>
<input type="checkbox" id="id_chk4" class="chkbox" value="4" />Check 4<br/>
<input type="checkbox" id="id_chk5" class="chkbox" value="5" />Check 5<br/>
<input type="checkbox" id="id_chk6" class="chkbox" value="6" />Check 6<br/>
<input type="checkbox" id="id_chk7" class="chkbox" value="7" />Check 7<br/>
</body>
</html>
Here is also another implementation similar to Outlooks multiple selection..
<script type="text/javascript">
function inRange(x, range)
{
return (x >= range[0] && x <= range[1]);
}
$(document).ready(function() {
var $chkboxes = $('.chkbox');
var firstClick = 1;
var lastClick = null;
var range = [];
$chkboxes.click(function(e) {
if(!e.shiftKey && !e.ctrlKey) {
$('#index-' + firstClick).prop('checked', false);
firstClick = $chkboxes.index(this) + 1;
if (firstClick !== null && firstClick !== ($chkboxes.index(this)+1)) {
$('#index-' + firstClick).prop('checked', true);
}
} else if (e.shiftKey) {
lastClick = $chkboxes.index(this) + 1;
if ((firstClick < lastClick) && !inRange(lastClick, range)) {
for (i = firstClick; i < lastClick; i++) {
$('#index-' + i).prop('checked', true);
}
range = [firstClick, lastClick];
} else if ((firstClick > lastClick) && !inRange(lastClick, range)) {
for (i = lastClick; i < firstClick; i++) {
$('#index-' + i).prop('checked', true);
}
range = [lastClick, firstClick];
} else if ((firstClick < lastClick) && inRange(lastClick, range)) {
for (i = 1; i < 100; i++) {
$('#index-' + i).prop('checked', false);
}
for (i = firstClick; i < lastClick; i++) {
$('#index-' + i).prop('checked', true);
}
range = [firstClick, lastClick];
}else if ((firstClick > lastClick) && inRange(lastClick, range)) {
for (i = 1; i < 100; i++) {
$('#index-' + i).prop('checked', false);
}
for (i = lastClick; i < firstClick; i++) {
$('#index-' + i).prop('checked', true);
}
range = [lastClick, firstClick];
}
}
});
});
This is jquery solution that I wrote and use:
All checkboxes have same class named chksel
For faster individual selection a class will carry the order
named chksel_index
Also each checkbox has an attribute named rg that contain same
index
var chksel_last=-1;
$('.chksel').click(function(ev){
if(ev.shiftKey){var i=0;
if(chksel_last >=0){
if($(this).attr('rg') >= chksel_last){
for(i=chksel_last;i<=$(this).attr('rg');i++){$('.chksel_'+i).attr('checked','true')}}
if($(this).attr('rg') <= chksel_last){for(i=$(this).attr('rg');i<=chksel_last;i++){$('.chksel_'+i).attr('checked','true')}}
}
chksel_last=$(this).attr('rg');
}else{chksel_last=$(this).attr('rg');}
})
this solution works for me, also ajax based for DataTables
https://jsfiddle.net/6ouhv7bw/4/
<table id="dataTable">
<tbody>
<tr>
<td><input type="checkbox"></td>
</tr>
<tr>
<td><input type="checkbox"></td>
</tr>
<tr>
<td><input type="checkbox"></td>
</tr>
<tr>
<td><input type="checkbox"></td>
</tr>
</tbody>
</table>
<script>
$(document).ready(function() {
var $chkboxes = $('#dataTable');
var $range = '#dataTable tbody';
var $first = false;
var $indexWrapp = 'tr';
var lastChecked = null;
var $checkboxes = 'input[type="checkbox"]';
$chkboxes.on('click',$checkboxes,function(e) {
if ($first===false) {
lastChecked = $(this).closest($indexWrapp).index();
lastCheckedInput = $(this).prop('checked');
$first=true;
return;
}
if (e.shiftKey) {
var start = lastChecked;
var end = $(this).closest($indexWrapp).index();
$( $range+' '+$indexWrapp).each(function() {
$currIndex=$(this).index();
if( $currIndex>=start && $currIndex<=end ){
$(this).find($checkboxes).prop('checked', lastCheckedInput);
}
})
}
lastCheckedInput = $(this).prop('checked');
lastChecked = $(this).closest($indexWrapp).index();
});
</script>
Here is the Elegant implementation. The idea is to store the first selected input to the lastChecked variable and when the user selects the input field with shiftKey we will run a loop and toggle the inBetween(boolean) and mark all the checkboxes with true value.
Inspired by Wesbos.
let checkboxes = document.querySelectorAll('.wrapper input[type="checkbox"]');
let lastChecked;
function logic(e) {
let inBetween = false;
if (e.shiftKey) {
checkboxes.forEach(checkbox => {
if (checkbox === this || checkbox === lastChecked) {
inBetween = !inBetween;
}
if (inBetween) checkbox.checked = true;
})
}
lastChecked = this;
}
checkboxes.forEach((checkbox, i) => checkbox.addEventListener('click', logic));
.wrapper {
display: flex;
flex-direction: column;
}
<div class="wrapper">
<input type="checkbox" name="one">
<input type="checkbox" name="two">
<input type="checkbox" name="three">
<input type="checkbox" name="four">
<input type="checkbox" name="five">
</div>

Categories