Use JavaScript to get value of the for each - javascript

I'm new using JavaScript. I need to get the value ${prdcts.precioUnidad} of the checked line. The idea is to set the total price in a dynamic way, so when the user checks or unchecks each line the value of total either adds the new value when checked, or subtracts the previous value when unchecked.
I tried to get the value using the getElement() methods, but I don't know how to access the value of the variable within that specific row.
This is the HTML:
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Ventas</title>
</head>
<body>
<center><h1>Venta de Productos</h1>
<form action="venta.htm" method="post">
<table id="tableID" border="4">
<tbody><tr>
<th>ID</th>
<th>Nombre</th>
<th>Valor</th>
<th>Comprado</th>
</tr>
<tr>
<td>2</td>
<td>Chupetin</td>
<td>5.0</td>
<td><input name="check" type="checkbox" value="2" label="2" path="prdcts"></td>
</tr>
<tr>
<td>3</td>
<td>Alfajor DDL</td>
<td>30.0</td>
<td><input name="check" type="checkbox" value="3" label="3" path="prdcts"></td>
</tr>
<tr>
<td>4</td>
<td>Sanguche Mila</td>
<td>60.0</td>
<td><input name="check" type="checkbox" value="4" label="4" path="prdcts"></td>
</tr>
</tbody></table>
<br>
<br>
<br>
<table border="4">
<tbody><tr>
<td>Total Compra: <input name="total" id="total" type="number" readonly="" value="0"></td>
</tr>
<tr>
<td>Monto Pagado: <input name="monto" id="monto" type="number" value="0"></td>
</tr>
<tr>
<td>Vuelto: <input name="vuelto" id="vuelto" type="number" readonly="" value="0"></td>
</tr>
<tr>
<td><input name="begin" onclick="calcularVuelto()" type="button" value="Calcular Vuelto"></td>
</tr>
</tbody></table>
<br>
<br>
<input name="clear" onclick="window.location.href = 'venta.htm'" type="button" value="Borrar venta">
<input name="begin" onclick="window.location.href = 'principal.htm'" type="button" value="Inicio">
<input name="confirm" type="submit" value="Confirmar Venta">
<br>
</form>
</center>
<script>
// Make it an Array with "Array.from" so we can use reduce() on it
var $$checkboxes = Array.from(document.querySelectorAll('input[name=check]')),
$total = document.getElementById('total');
// For each checkbox
$$checkboxes.forEach(function ($checkbox) {
// When its value changes, update total
$checkbox.addEventListener('change', updateTotal);
});
function updateTotal() {
// For each checkbox
alert("aca");
var total = $$checkboxes.reduce(function (sum, $checkbox) {
// If it's checked
alert("aca2")
if ($checkbox.checked) {
var price = $checkbox.parentNode.parentNode // parent <tr>
.querySelectorAll('td')[2].innerText.trim(); // remove spaces
// Add price to the sum
return sum + parseFloat(price);
} else {
// If it's not checked, just return the current sum
return sum;
}
}, 0);
$total.value = total.toFixed(2); // Always 2 decimals
}
function calcularVuelto() {
var total = document.getElementById("total").value;
var pago = document.getElementById("monto").value;
var fTotal = parseFloat(total);
var fPago = parseFloat(pago);
totalResta = fPago - fTotal;
document.getElementById("vuelto").value = totalResta;
}
</script>
</body></html>

You can use Array.prototype.reduce() to calculate the total:
// Make it an Array with "[].slice.call" so we can use reduce() on it
var $$checkboxes = [].slice.call(document.querySelectorAll('input[name=check]')),
$total = document.getElementById('total');
// For each checkbox
$$checkboxes.forEach(function ($checkbox) {
// When its value changes, update total
$checkbox.addEventListener('change', updateTotal);
});
function updateTotal() {
// For each checkbox
var total = $$checkboxes.reduce(function (sum, $checkbox) {
// If it's checked
if ($checkbox.checked) {
var price = $checkbox.parentNode.parentNode // parent <tr>
.querySelectorAll('td')[2].innerText.trim(); // remove spaces
// Add price to the sum
return sum + parseFloat(price);
} else {
// If it's not checked, just return the current sum
return sum;
}
}, 0);
$total.value = total.toFixed(2); // Always 2 decimals
}
<table border="4">
<tr><th>ID</th> <th>Nombre</th> <th>Valor</th> <th>Comprado</th> </tr>
<tr><td>x</td><td>X</td><td>5.99</td><td><input name="check" type="checkbox" value="x" label="X"/></td></tr>
<tr><td>y</td><td>Y</td><td>3.95</td><td><input name="check" type="checkbox" value="y" label="Y"/></td></tr>
<tr><td>z</td><td>Z</td><td>14.20</td><td><input name="check" type="checkbox" value="z" label="Z"/></td></tr>
</table>
<p>Total Compra: <input name="total" id="total" type="number" value="0" readonly/></p>

The checked flag is either on or off. It doesn't take an argument. So it looks like
<input type="checkbox" name="name" checked> checked </input>
<br/>
<input type="checkbox" name="name"> unchecked</input>
In your code you'll need something like: ${prdcts.idProducto ? "checked" : ""}

Related

Select only checkboxes that are checked in a column

I have an html table that has 5 columns. 2 columns are checkboxes (entry and high) and the other 3 are data. I have 2 buttons, one is called entry and the other high. When a user clicks on the high button, I'm trying to check the column (high) only and get all that is checked, take those values and average them.
The same with entry, when the entry button is clicked, check only the checkboxes in column (entry) and take those values and average them.
So far I have a function to check both columns but not sure how to separately check and separate the columns to each button function only. I have tried the below, but the GetHigh function doesn't work.
Any points in the right direction would be appreciated!
Table
<td><input type="checkbox" class="entry" id="entry" value="{{$sup->entry}}" name="rows[]"></td>
<td><input type="checkbox" class="high" id="high" value="{{$sup->high}}" name="rows[]"></td>
<td><span style="color: #007E33">{{$sup->entry}} </span></td>
<td><span style="color: #007E33">{{$sup->high}} </span></td>
<td><span style="color: #007E33">{{$sup->days}} </span></td>
Buttons
<a href="#here" class="btn btn-primary btn-pill w-10" id="entry" onclick="GetEntry()">
Entry Average
</a>
<a href="#here" class="btn btn-primary btn-pill w-10" id="high" onclick="GetHigh()">
High Average
</a>
Javascript
function GetEntry() {
//Create an Array.
var selected = new Array();
//Reference the Table.
var supTable = document.getElementById("supTable");
//Reference all the CheckBoxes in Table. I WANT ONLY THE ENTRY COLUMN
var entry = supTable.getElementsByTagName("INPUT");
// Loop and push the checked CheckBox value in Array.
for (var i = 0; i < entry.length; i++) {
if (entry[i].checked) {
selected.push(entry[i].value);
}
}
// alert("Average: " + calculate(selected));
$(".text-message").text("Average: " + calculate(selected)).show();
}
function GetHigh() {
//Create an Array.
var selected = new Array();
//Reference the Table.
var supTable = document.getElementById("supTable");
//Reference all the CheckBoxes in Table. I WANT ONLY THE ENTRY COLUMN
var entry = supTable.getElementsByName("High");
// Loop and push the checked CheckBox value in Array.
for (var i = 0; i < high.length; i++) {
if (high[i].checked) {
selected.push(high[i].value);
}
}
// alert("Average: " + calculate(selected));
$(".text-message").text("Average: " + calculate(selected)).show();
}
getElementsByName is used to select HTML where their name="" attribute matches what you've entered, in this case 'High'. But your HTML in the example shows a different name.
You want to use querySelectorAll('high') to get all of the elements that have class="high" set.
You can use a css selector to get the cells of your table
const getCheckboxes = columnIndex =>document.querySelectorAll(`tbody td:nth-child(${columnIndex}) input:checked`);
Or add a common class and select by the class to the checkboxes
const getCheckboxes = className =>document.querySelectorAll(`tbody .${className}:checked`);
Basic example:
const getCheckedCheckboxesClassName = className => document.querySelectorAll(`tbody .${className}:checked`);
const getCheckedCheckboxesByIndex = columnIndex =>document.querySelectorAll(`tbody td:nth-child(${columnIndex}) input:checked`);
const sumValues = cbs => [...cbs].reduce((total, cb) => total + +cb.value, 0);
const getTotal = (group) => {
const cbs = getCheckedCheckboxesClassName(group);
const value = sumValues(cbs);
console.log(value);
}
const getTotalIndex = (index) => {
const cbs = getCheckedCheckboxesByIndex(index);
const value = sumValues(cbs);
console.log(value);
}
<button type="button" onclick="getTotal('low'); getTotalIndex(1)">low</button>
<button type="button" onclick="getTotal('high'); getTotalIndex(2)">high</button>
<table>
<tbody>
<tr>
<td><input class="low" type="checkbox" value="1" /></td>
<td><input class="high" type="checkbox" value="10" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="2" /></td>
<td><input class="high" type="checkbox" value="20" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="3" /></td>
<td><input class="high" type="checkbox" value="30" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="4" /></td>
<td><input class="high" type="checkbox" value="40" /></td>
</tr>
<tr>
<td><input class="low" type="checkbox" value="5" /></td>
<td><input class="high" type="checkbox" value="50" /></td>
</tr>
</tbody>
</table>

Sum of <td> value from dynamic generated table based on checkbox attribute

I have been trying to find the sum of balance (column) of the selected checkbox as below
HTML
<h2>Sum of selected invoices is AED <div class="totalsum"></div></h2>
<table border="1" id="rcpt"><tr><th><input type="checkbox" onClick="selectAll(this),updateSum()" /></th><th>Invoice No.</th><th>Date</th><th>Balance</th></tr>
<tr>
<td><input type="checkbox" class="checkbox" name="select[]" value="2" onclick="updateSum()" /></td>
<td>INV-2020-0001</a></td>
<td>31-05-2020</td>
<td class="balance">56,842.50</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" name="select[]" value="3" onclick="updateSum()" /></td>
<td>INV-2020-0002</a></td>
<td>10-06-2020</td>
<td class="balance">96,962.60</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" name="select[]" value="4" onclick="updateSum()" /></td>
<td>INV-2020-0003</a></td>
<td>15-06-2020</td>
<td class="balance">100,251.20</td>
</tr>
</table>
PHP (Edit)
<?php
$query = 'QUERY';
$sql = mysqli_query($conn, $query);
while ($result = mysqli_fetch_array($sql)) {
$id = $result['id'];
$inv_no =$result['cinv_no'];
$inv_date = $result['cinv_date'];
$inv_bal = $result['cinv_bal'];
echo '<tr>';
echo '<td><input type="checkbox" class="checkbox" name="select[]" value="'.$id.'" onclick="updateSum()" /></td>';
echo '<td>'.$cinv_no.'</a></td>';
echo '<td>'.date("d-m-Y", strtotime($cinv_date)).'</td>';
echo '<td class="balance">'.number_format($cinv_bal,2).'</td>';
echo '</tr>';
}
?>
Javascript (JS + Jquery)
function selectAll(source) {
select = document.getElementsByName('select[]');
for(var i=0, n=select.length;i<n;i++) {
select[i].checked = source.checked;
}
}
function updateSum() {
var total = 0;
var select = $(".checkbox:checked");
var balance = $(".balance");
select.each(function() { total += parseFloat(balance.html().replace(/,/g, ''));})
$(".totalsum").html(total.toFixed(2));
}
Whenever I select a random checkbox, it adds the balance in order(first to last) rather than the selected balances
JSFiddle https://jsfiddle.net/cj19zban/
You need to find the .balance related to the checked checkbox.
function updateSum() {
var total = 0;
var select = $(".checkbox:checked");
select.each(function() {
// get the balance relative to the checked checkbox
const balance = select.parents('tr').find('.balance');
total += parseFloat(balance.html().replace(/,/g, ''));
})
$(".totalsum").text(total.toFixed(2));
}
However, this is somewhat inefficient. I would do something slightly different. You can store the relative balance as the value of the input.. which saves time figuring out which element to get it from.
const updateTotal = () => {
const total = $(".checkbox:checked")
.map((index, checkedCheckbox) => parseFloat(checkedCheckbox.dataset.value))
.toArray()
.reduce((acc, cur) => acc + cur, 0);
$('#totalsum').text(total.toFixed(2));
}
const toggleAll = (checked) => {
$('.checkbox').each((index, checkbox) => {
checkbox.checked = checked;
});
}
$('.checkbox').click(updateTotal);
$('#selectAll').click(function() {
toggleAll($(this).is(':checked'));
updateTotal();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Receipts</h1>
<h2>Sum of selected invoices is AED
<div id="totalsum">0.00</div>
</h2>
<table border="1" id="rcpt">
<tr>
<th><input id='selectAll' type="checkbox" /></th>
<th>Invoice No.</th>
<th>Date</th>
<th>Balance</th>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" name="select[]" value="2" data-value="56842.50" /></td>
<td>INV-2020-0001</td>
<td>31-05-2020</td>
<td class="balance">56,842.50</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" name="select[]" value="3" data-value="96962.60" /></td>
<td>INV-2020-0002</td>
<td>10-06-2020</td>
<td class="balance">96,962.60</td>
</tr>
<tr>
<td><input type="checkbox" class="checkbox" name="select[]" value="4" data-value="100251.20" /></td>
<td>INV-2020-0003</td>
<td>15-06-2020</td>
<td class="balance">100,251.20</td>
</tr>
</table>
I also removed some trailing </a> that seems to break your HTML.

Button not being enabled after click on checkboxes

So, I have created a table with checkboxes and I want the user to check at least two options in order to enable the button to submit the answers.
HTML
<body>
<h1>Checked two options</h1>
<br />
<p>What are some of your favorite dishes?</p>
<table id="tblFoods">
<tr>
<td><input id="chkPizza" type="checkbox" /><label for="chkPizza">Pizza</label></td>
</tr>
<tr>
<td><input id="chkLasagna" type="checkbox" /><label for="chkLasagna">Lasagna</label></td>
</tr>
<tr>
<td><input id="chkPasta" type="checkbox" /><label for="chkPasta">Pasta</label></td>
</tr>
<tr>
<td><input id="chkBarbecue" type="checkbox" /><label for="chkBarbecue">Barbecue</label></td>
</tr>
</table>
<br />
<input type="submit" id="mybtn" disabled value="Submit" onclick="EnableButton()" />
</body>
And I have this function, but it's not working. I'm using a looping to count how many options have been checked by the user, but it doesn't work.
JS
function EnableButton() {
var tblFoods = document.getElementById("tblFoods");
var checkeds = tblFoods.getElementsByTagName("INPUT");
var counter = 0;
for (let i = 0; i < marcados.length; i++) {
if (checkeds[i].checked) {
counter++;
}
}
if (counter >= 2) {
document.getElementById("mybtn").disabled = false;
} else {
document.getElementById("mybtn").disabled = true;
}
}
What am I doing wrong?
You need to check for whether the button needs to be enabled when the inputs get checked, not when the button gets clicked.
The nicest, most concise way to do this is:
const table = document.querySelector('#tblFoods');
table.addEventListener('change', () => {
const checkedCount = [...table.querySelectorAll('input')].reduce((a, input) => a + input.checked, 0);
document.getElementById("mybtn").disabled = checkedCount < 2;
});
<h1>Checked two options</h1>
<br/>
<p>What are some of your favorite dishes?</p>
<table id="tblFoods">
<tr>
<td><input id="chkPizza" type="checkbox" /><label for="chkPizza">Pizza</label></td>
</tr>
<tr>
<td><input id="chkLasagna" type="checkbox" /><label for="chkLasagna">Lasagna</label></td>
</tr>
<tr>
<td><input id="chkPasta" type="checkbox" /><label for="chkPasta">Pasta</label></td>
</tr>
<tr>
<td><input id="chkBarbecue" type="checkbox" /><label for="chkBarbecue">Barbecue</label></td>
</tr>
</table>
<br />
<input type="submit" id="mybtn" disabled value="Submit" />
Your original code, tweaked, works too, but is pretty verbose in comparison.
document.querySelector('#tblFoods').addEventListener('change', () => {
var tblFoods = document.getElementById("tblFoods");
var checkeds = tblFoods.getElementsByTagName("INPUT");
var counter = 0;
for(let i =0; i < checkeds.length;i++)
{
if(checkeds[i].checked)
{
counter++;
}
}
if(counter>=2)
{
document.getElementById("mybtn").disabled = false;
}
else
{
document.getElementById("mybtn").disabled = true;
}
});
<h1>Checked two options</h1>
<br/>
<p>What are some of your favorite dishes?</p>
<table id="tblFoods">
<tr>
<td><input id="chkPizza" type="checkbox" /><label for="chkPizza">Pizza</label></td>
</tr>
<tr>
<td><input id="chkLasagna" type="checkbox" /><label for="chkLasagna">Lasagna</label></td>
</tr>
<tr>
<td><input id="chkPasta" type="checkbox" /><label for="chkPasta">Pasta</label></td>
</tr>
<tr>
<td><input id="chkBarbecue" type="checkbox" /><label for="chkBarbecue">Barbecue</label></td>
</tr>
</table>
<br />
<input type="submit" id="mybtn" disabled value="Submit" />
You have to handle the changes on each checkbox element separately and finally, the submit button. You can do something like the below.
Note: See how the onClick event handlers are used on each input type checkbox element and on the submit button separately. Also, we have to reset everything when submitting.
A possible solution:
let checks_counter = 0;
function EnableButton(checkbox) {
if (checkbox.checked) {
checks_counter++;
}
if (checks_counter > 2) {
document.getElementById("mybtn").disabled = false;
} else {
document.getElementById("mybtn").disabled = true;
}
}
function submitHandler() {
var elements = document.getElementsByTagName('input');
//unchecking everything
for (var i = elements.length; i--;) {
if (elements[i].type == 'checkbox') {
elements[i].checked = false;
}
}
//resetting the counter and disabling the button
checks_counter = 0;
document.getElementById("mybtn").disabled = true;
}
<body>
<h1>Checked two options</h1>
<br/>
<p>What are some of your favorite dishes?</p>
<table id="tblFoods">
<tr>
<td><input id="chkPizza" type="checkbox" onChange="EnableButton(this)" /><label for="chkPizza">Pizza</label></td>
</tr>
<tr>
<td><input id="chkLasagna" type="checkbox" onChange="EnableButton(this)" /><label for="chkLasagna">Lasagna</label></td>
</tr>
<tr>
<td><input id="chkPasta" type="checkbox" onChange="EnableButton(this)" /><label for="chkPasta">Pasta</label></td>
</tr>
<tr>
<td><input id="chkBarbecue" type="checkbox" onChange="EnableButton(this)" /><label for="chkBarbecue">Barbecue</label></td>
</tr>
</table>
<br />
<input type="submit" id="mybtn" disabled value="Submit" onclick="submitHandler()" />
</body>
You need to call your Enable function when you check boxes. Here's a working example: https://codesandbox.io/s/proud-architecture-ou5l2?file=/src/index.js
using your existing code:
var tblFoods = document.getElementById("tblFoods");
var checkeds = tblFoods.querySelectorAll("input");
const btn = document.getElementById("mybtn");
function enableButton() {
var counter = 0;
for (let i = 0; i < checkeds.length; i++) {
if (checkeds[i].checked) {
counter++;
}
}
if (counter >= 2) {
btn.disabled = false;
} else {
btn.disabled = true;
}
}
const handleClick = () => {
enableButton();
// do whatever else you need in here
};
checkeds.forEach((box) => box.addEventListener("click", handleClick));
You have to run your function when the user select the food, not when the user click the button. A simple solution is removing the onclick event from the button and adding the onchange event in every input:
<h1>Checked two options</h1>
<br />
<p>What are some of your favorite dishes?</p>
<table id="tblFoods">
<tr>
<td><input id="chkPizza" type="checkbox" onchange="EnableButton()" /><label for="chkPizza">Pizza</label></td>
</tr>
<tr>
<td><input id="chkLasagna" type="checkbox" onchange="EnableButton()" /><label for="chkLasagna">Lasagna</label>
</td>
</tr>
<tr>
<td><input id="chkPasta" type="checkbox" onchange="EnableButton()" /><label for="chkPasta">Pasta</label></td>
</tr>
<tr>
<td><input id="chkBarbecue" type="checkbox" onchange="EnableButton()" /><label for="chkBarbecue">Barbecue</label>
</td>
</tr>
</table>
<br />
<input type="submit" id="mybtn" disabled value="Submit" />
You could use something like:
document.querySelectorAll("input[type='checkbox']").forEach(e => e.addEventListener("click", () => {
const submitButton = document.querySelector("#mybtn");
if (!submitButton) return;
const checkedInputs = document.querySelectorAll("#tblFoods input[type='checkbox']:checked").length;
submitButton.disabled = checkedInputs < 2;
}));
In other words, every time a checkbox is clicked, a check is run on how many checkboxes are checked in total. If this amount is greater than or equal to two, the button is enabled, otherwise it is disabled.
Maybe i am wrong but since u had initialized counter = 0, every time that the function its called, it will automatically set to 0, so u should declare it globally in order to be an effective counter.
var counter = 0;
function EnableButton()
{
var tblFoods = document.getElementById("tblFoods");
var checkeds = tblFoods.getElementsByTagName("INPUT");
for(let i =0; i < checkeds.length;i++)
{
if(checkeds[i].checked)
{
counter++;
}
}
if(counter>=2)
{
document.getElementById("mybtn").disabled = false;
}
else
{
document.getElementById("mybtn").disabled = true;
}
}

Where do I implement the getElementById in my JavaScript function?

Background: For my website I have to count the number of checked checkboxes in a table. Depending on the result, there is then a different 'output'. As long as fewer than or equal to 2 checkboxes are checked --> output A. If more than 2 boxes are checked OR the first checkbox is checked --> output B.
Now to my problem: I specifically don't understand this line of code:
const checked = [...this.querySelectorAll(".choice:checked")].map(inp => +inp.value);
If I understand correctly, it checks all input fields in the form, adds and converts the results. But how can I implement an ID here that I only give to the first checkbox in order to solve the problem?
And another question: Can I then link the values ​​with a logical operator?
My code:
.hide {
display: none;
}
<form id="listForm">
<table>
<tbody>
<tr id="G">
<td><b>G</b></td>
<td></td>
<td><input type="checkbox" class="choice" id="cbg" name="choiceG" value="1"></td>
</tr>
<tr>
<td id="A"><b>A</b></td>
<td></td>
<td><input type="checkbox" class="choice" name="choiceA" value="1"></td>
</tr>
<tr>
<td id="B"><b>B</b></td>
<td></td>
<td><input type="checkbox" class="choice" name="choiceB" value="1"></td>
</tr>
<tr>
<td id="C"><b>C</b></td>
<td></td>
<td><input type="checkbox" class="choice" name="choiceC" value="1"></td>
</tr>
<tr>
<td colspan="2" ;="" style="text-align:right;"><b>Sum:</b></td>
<td><input disabled="" type="text" size="2" name="total" id="total" value="0"></td>
</tr>
</tbody>
</table>
</form>
<div id="showwhen2" class="hide">
<p>2 or less boxes checked; first box is unchecked</p>
</div>
<div id="showwhen3" class="hide">
<p>first box or more than two boxes are checked</p>
</div>
<script>
document.getElementById("listForm").addEventListener("input", function() {
let sum = 0;
let sumg = 0;
const checked = [...this.querySelectorAll(".choice:checked")].map(inp => +inp.value);
const checkedg = [...this.querySelectorAll(".choice:checked")].map(inp => +inp.value);
if (checked.length > 0) sum = checked.reduce((a, b) => a + b);
if (checkedg.length > 0) sumg = checkedg.reduce((a, b) => a + b);
console.log(sum);
console.log(sumg);
document.getElementById("total").value = sumg + sum;
document.getElementById("showwhen3").classList.toggle("hide", sum < 3 || sumg <1);
document.getElementById("showwhen2").classList.toggle("hide", sum > 2);
});
</script>
This seems really overcomplicated.
const checkedCount = this.querySelectorAll(".choice:checked").length
if (checkedCount > 2 || this.querySelector('input#cbg').checked) {
//output B
} else {
//output A
}
querySelectorAll returns a list of all elements that match the selector (i. e. all checked inputs) and querySelector just one element. # is selector syntax for element ids.

How to get values to the outside from three functions and update them in real time?

I have a table which lets users to add number of participants for an event. in it I used input type number field to get number of participants. then I calculate how much fee they have to pay for each passenger type. I have 3 passenger types.
My table looks like this,
I use keyup mouseup bind to get the input value by user and multiplied it with fee for one participant.
var totalAdults;
jQuery("#number_adults").bind('keyup mouseup', function () {
var numOfAdults = jQuery("#number_adults").val();
totalAdults = numOfAdults * adultFee;
});
I have 3 of above functions to calculate and real time display how much fee that they have to pay in each passenger type.
Now I need to get the total sum of all three passenger type fees and display/update it in real time to the user, at the end of my table.
I tried making each passenger type total value global and calculating it's sum, but I get an error saying missing semicolon error linked to this MDN article
I'm stuck here. how can I get total value on all three passenger types outside their respective functions and display that value correctly in real time? (when they update number of passengers, total for passenger type is changing, I need to change final total accordingly). please help
Update:
this is the html table that I used. this get repeated another two times for other two passenger types.
var adultFee = 150;
var finalTotal = 0;
jQuery("#number_adults").bind('keyup mouseup', function() {
var numOfAdults = jQuery("#number_adults").val();
totalAdults = numOfAdults * adultFee;
jQuery("#adult_amount").html(totalAdults);
// console.log(totalAdults);
finalTotal = finalTotal + totalAdults;
console.log(finalTotal);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<tr>
<td style="font-weight: 600;">Adult</td>
<td id="adult_price" name="adult_price">150.00</td>
<td>
<input id="number_adults" max="3" min="1" name="number_adults" type="number" value="0" class="form-control">
</td>
<td name="amount">
<p id="adult_amount"></p>
</td>
</tr>
This is how I tried to get the final total, it doesn't display any result
jQuery(document).on('change', '#adult_amount', function() {
finalTotal = finalTotal+totalAdults;
alert(finalTotal);
});
I made a working example for you.
$('.inputs').each(function(){
$(this).on('change keyup', function(){
let sumTotal = 0;
$('.inputs').each(function(){
sumTotal += $(this).val() * +$(this).parent().next().data('price');
});
$('.total').text(`${sumTotal} $`);
});
});
td:nth-child(3),
th:nth-child(3){
text-align:center;
}
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row justify-content-center">
<div class="col-12">
<table class="table table-hover">
<thead>
<tr>
<th></th>
<th>QTY</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Child</td>
<td><input type="number" class="inputs form-control" value="0" min="0" max="999"></td>
<td class="price" data-price="150">150 $</td>
</tr>
<tr>
<td>Adult</td>
<td><input type="number" class="inputs form-control" value="0" min="0" max="999"></td>
<td class="price" data-price="200">200 $</td>
</tr>
<tr>
<td>Adult Plus</td>
<td><input type="number" class="inputs form-control" value="0" min="0" max="999"></td>
<td class="price" data-price="250">250 $</td>
</tr>
<tr>
<td>Total - </td>
<td></td>
<td class="total">0.00 $</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
(https://codepen.io/bichiko/pen/JQWomy)
Here is a solution which should do what you need.
Compared to your code, the key changes are:
Use classes instead of IDs to identify the elements within each row. This means you can handle changes to all your fields using the same event handling code. I've given all your quantity fields the .qty class, and then bound the event to that class, so all elements with that class will run the same function.
Within the function, I've stripped out all direct references to fields - instead, to get the price field, and the total field for the relevant type, the code uses the positions of the fields relative to each other in the page, it uses the .parent(), .next(), and .prev() functions to find the total and amount fields which are within the same table row as the altered quantity field (which will always be this inside the event handler), so that it does the calculations on the right fields.
To calculate the final overall total, I've defined a separate function. Again this uses a class selector to identify all the "amount" fields, and add each of those values together to get the total. Since this function is triggered at the end of the event handler, it will always update the grand total whenever one of the quantities is updated.
Other minor changes:
use .on() instead of the deprecated .bind()
jQuery(".qty").on('keyup mouseup', function() {
var tdElement = jQuery(this).parent();
var qty = parseInt(this.value);
var fee = parseFloat(tdElement.prev(".price").text());
var typeTotal = qty * fee;
tdElement.next(".amount").html(typeTotal);
calcFinalTotal();
});
function calcFinalTotal()
{
var finalTotal = 0;
$(".amount").each(function() {
finalTotal += parseFloat($(this).text());
});
$("#total").text(finalTotal);
}
td, th
{
border: solid 1px #cccccc;
padding: 5px;
text-align:left;
}
table {
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<th>Passenger Type</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<tr>
<th>Adult</th>
<td class="price">150.00</td>
<td>
<input max="3" min="1" name="number_adults" type="number" value="0" class="form-control qty">
</td>
<td class="amount">0
</td>
</tr>
<tr>
<th>Type 2</th>
<td class="price" id="type3_price">200.00</td>
<td>
<input max="3" min="1" name="number_type" type="number" value="0" class="form-control qty">
</td>
<td class="amount">0
</td>
</tr>
<tr>
<th>Type 3</th>
<td class="price" id="type3_price">200.00</td>
<td>
<input max="3" min="1" name="number_type" type="number" value="0" class="form-control qty">
</td>
<td class="amount">0
</td>
</tr>
<tr>
<th colspan="3">Grand Total</th>
<td id="total"></td>
</tr>
</table>
You can simply loop on every rows on the table and calculate the total sum and also the individual. Here i done by the dynamic method. if the total of each passenger is inserted in a unique input, then you can access from that input. Otherwise please follow the method
$(document).on('keyup mouseup','.qty', function() {
calculate();
});
function calculate(){
var finalTotal = 0;
var old = 0;
var mature = 0;
var adult = 0;
$('.qty').each(function(key,value){
$qty = $(this).val();
$type = $(this).attr('data-type');
$amount = $(this).parent().siblings('.adult_price').html();
$total = Number($qty) * parseFloat($amount);
$(this).parent().siblings('.amount').html($total);
finalTotal += $total;
if($type == 'adult')
adult += parseFloat($total);
else if($type == 'mature')
mature += parseFloat($total);
else if($type == 'old')
old += parseFloat($total);
});
$('.grandTotal').html(finalTotal);
// console.log('Adult',adult);
// console.log('Mature',mature);
// console.log('Old',old);
}
table {
border-collapse: collapse;
width: 80%;
}
th, td {
text-align: left;
padding: 8px;
}
tr:nth-child(even){background-color: #f2f2f2}
th {
background-color: #4CAF50;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Passenger Types</th>
<th>Amount</th>
<th>Qty</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>Adult</b></td>
<td class="adult_price" name="adult_price">150.00</td>
<td>
<input max="3" min="1" name="number_adults" type="number" value="0" class="form-control qty" data-type="adult">
</td>
<td name="amount" class='amount'></td>
</tr>
<tr>
<td><b>Mature</b></td>
<td class="adult_price" name="adult_price">200.50</td>
<td>
<input max="3" min="1" name="number_adults" type="number" value="0" class="form-control qty" data-type="mature">
</td>
<td name="amount" class='amount'></td>
</tr>
<tr>
<td><b>Old</b></td>
<td class="adult_price" name="adult_price">150.00</td>
<td>
<input max="3" min="1" name="number_adults" type="number" value="0" class="form-control qty" data-type="old">
</td>
<td name="amount" class='amount'></td>
</tr>
<tr>
<td colspan="3"><b>Grand Total</b></td>
<td class='grandTotal'>100</td>
</tr>
</tbody>
</table>
jQuery is very flexible use class instead of id. If you use inputs, selects, etc you should delegate the input or change event to them.
$('input').on('input', function() {...
input event will trigger as soon as user types or selects on or to an input tag. change event will trigger when a user types or selects on or to an input and then clicks (unfocus or blur event) elsewhere.
The HTML is slightly modified for consistency. Note that there are 2 extra inputs per <tr>.
When using input inside tables you can traverse the DOM by first referencing the imputed/changed/clicked tag as $(this) then climb up to the parent <td> and from there either go to the next <td> using .next() or go to the previous <td> using .prev(). Once you get to a neighboring <td> use .find() to get the input within. When extracting a number from an input it is normally a string but with jQuery method .val() it should extract input value as a number automatically. Details commented in demo.
/*
//A - Any tag with the class of .qty that the user inputs data into triggers a function
//B - Get the value of the imputed .qty (ie $(this))
//C - reference $(this) parent <td> go to the next <td> then find a tag with the class .price and get its value
//D - reference $(this) parent <td> go to the previous <td> then find a tag with the class of .total then set its value to the product of qty and price and fix it with hundredths (.00 suffix)
//E - Declare an empty array
//F - Get the value of each .total, convert it into a number then push the number into the empty array
//G - Use .reduce() to get the sum of all values within the array then fix it with hundredths (.00 suffix) and set it as the value of .grand
*/
$('.qty').on('input', function() { //A
var qty = $(this).val(); //B
var price = $(this).parent().prev('td').find('.price').val(); //C
$(this).parent().next('td').find('.total').val((qty * price).toFixed(2)); //D
var totals = []; //E
$('.total').each(function() {
totals.push(Number($(this).val()));
}); //F
$('.grand').val(totals.reduce((sum, cur) => sum + cur).toFixed(2)); //G
});
table {
table-layout: fixed;
}
td {
width: 6ch
}
[readonly] {
border: 0;
width: 6ch;
text-align: right
}
[type=number] {
text-align: right
}
<table>
<tr>
<td style="font-weight: 600;">Adult</td>
<td><input class="price" name='price' value='150.00' readonly></td>
<td>
<input class="qty" name="qty" min="0" max="3" type="number" value="0" class="form-control">
</td>
<td>
<input class="total" name='total' readonly>
</td>
</tr>
<tr>
<td style="font-weight: 600;">Senior</td>
<td><input class="price" name='price' value='100.00' readonly></td>
<td>
<input class="qty" name="qty" min="0" max="3" type="number" value="0" class="form-control">
</td>
<td>
<input class="total" name='total' readonly>
</td>
</tr>
<tr>
<td style="font-weight: 600;">Child</td>
<td><input class="price" name='price' value='75.00' readonly></td>
<td>
<input class="qty" name="qty" min="0" max="3" type="number" value="0">
</td>
<td>
<input class="total" name='total' readonly>
</td>
</tr>
<tr>
<td colspan='3' style='text-align:right;'>Total</td>
<td><input class='grand' name='grand' value='0' readonly></td>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This is axample of yours problem, try using object
var data = {a:0, b:0, c: 0}
function one (){
data.a = data.a + 10
console.log(data.a)
total()
}
function two (){
data.b = data.b + 10
total()
console.log(data.b)
}
function three () {
data.c = data.c + 30
total()
console.log(data.c)
}
function total () {
var totaly = data.a + data.b + data.c
console.log('Total input :', totaly)
}
<button onclick="one()"> get A </button>
<button onclick="two()"> get B</button>
<button onclick="three()"> get C </button>

Categories

Resources