I have a table with three columns: item, price and a checkbox. I want to calculate the subtotal but only include the prices with a checked checkbox. The code I have so far is a mix of various bits that work on its own; however right now I get the error message "TypeError: Cannot read properties of undefined (reading 'innerHTML')". What am I doing wrong?
function calculate() {
const ele = document.getElementsByTagName('input');
let table = document.getElementById("myTable");
let tr = table.getElementsByTagName("tr");
let subTotal = 0;
for (var i = 0; i < ele.length; i ) {
let td = tr[i].getElementsByTagName("td")[1];
let price = td[i].innerHTML;
if (ele[i].type == 'checkbox' && ele[i].checked == true)
subTotal = price;
}
document.getElementById("val").innerHTML = "The subtotal is " subTotal;
}
<!DOCTYPE html>
<html>
<body>
<table id="myTable">
<tr>
<td>T-Shirt</td>
<td>9.99</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<td>Pants</td>
<td>49.99</td>
<td><input type="checkbox"></td>
</tr>
</table>
<span id="val">The subtotal is 0</span>
<button onclick="calculate()">Calculate subtotal</button>
</html>
CodePudding user response:
You have to change the line td[i]
because it's not defined as the error suggests. So, consider using bare td
and accessing its innerText
. It'll return a string with the value, which you have to convert to a float number with parseFloat
. Finally, you must set the precision you want to subTotal
so that it will print with the number of decimals you want.
function calculate() {
const ele = document.getElementsByTagName('input');
let table = document.getElementById("myTable");
let tr = table.getElementsByTagName("tr");
let subTotal = 0;
for (var i = 0; i < ele.length; i ) {
let td = tr[i].getElementsByTagName("td")[1];
let price = parseFloat(td.innerText); // change here
if (ele[i].type == 'checkbox' && ele[i].checked == true)
subTotal = price;
}
document.getElementById("val").innerHTML = "The subtotal is " subTotal.toFixed(2); // and set precision here
}
<!DOCTYPE html>
<html>
<body>
<table id="myTable">
<tr>
<td>T-Shirt</td>
<td>9.99</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<td>Pants</td>
<td>49.99</td>
<td><input type="checkbox"></td>
</tr>
</table>
<span id="val">The subtotal is: </span>
<button onclick="calculate()">Calculate subtotal</button>
</html>
CodePudding user response:
Problem with your code is simple. You referenced the td and than you try to reference it again.
let td = tr[i].getElementsByTagName("td")[1];
let price = td[i].innerHTML;
Should be
const td = tr[i].getElementsByTagName("td")[1];
const price = td.innerHTML;
If you use a value on the checkbox, you can just loop over the checked inputs and calculate the total using the values. No need to look up cell contents.
function calculate() {
const checkedInputs = document.querySelectorAll("#myTable input:checked");
const total = Array.from(checkedInputs).reduce(function(total, cb) {
return total cb.value;
}, 0);
document.querySelector("#val").textContent = "The subtotal is " total.toFixed(2);
}
<table id="myTable">
<tr>
<td>T-Shirt</td>
<td>9.99</td>
<td><input type="checkbox" value="9.99"></td>
</tr>
<tr>
<td>Pants</td>
<td>49.99</td>
<td><input type="checkbox" value="49.99"></td>
</tr>
</table>
<span id="val">The subtotal is 0</span>
<button onclick="calculate()">Calculate subtotal</button>
CodePudding user response:
You can iterate trhough checkbox and going up until the previous td
function calculate() {
let chckboxes = document.querySelectorAll('#myTable input:checked');
let sum = 0;
chckboxes.forEach((itm) => {
let val = parseFloat(itm.parentElement.previousElementSibling.innerHTML)
sum = val;
});
document.getElementById("val").innerHTML = "The subtotal is " sum;
}
<!DOCTYPE html>
<html>
<body>
<table id="myTable">
<tr>
<td>T-Shirt</td>
<td>9.99</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<td>Pants</td>
<td>49.99</td>
<td><input type="checkbox"></td>
</tr>
</table>
<span id="val">The subtotal is 0</span>
<button onclick="javascript:calculate()">Calculate subtotal</button>
</html>