'How to get order total if quantity is updated
Order entry form contains product name, price and quantity columns:
<table id="order-products" class="mobileorder-table">
<colgroup>
<col style="width: 80%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>
Product1
</td>
<td>
<span class="mobileorder-price">0,98</span>
</td>
<td>
<input data-product="4750211645618" class="quantity" id="product_Soodkogus" name="product.Soodkogus"
type="number" min="0" max="999999" value=""
onblur="orderSumRefresh()" />
</td>
</tr>
</tbody>
</table>
Order total <p id="js-doksumma"></p>
If quantity is changed, order total value should updated. I tried
<script>
function parseFloatFormatted(txt) {
if (typeof txt !== 'string' || txt === null || txt === "") {
return 0
}
return parseFloat(txt.replace(',', '.').replace(' ', ''))
}
function orderSumRefresh() {
let totalAmount = 0
const table = document.getElementById("order-products")
table.rows.forEach((row) => {
//for (let i in table.rows) {
// const row = table.rows[i]
const hind = row.cells[1].querySelector(".mobileorder-price").value
const kogus = row.cells[2].querySelector(".quantity").value
const rowSum = Math.round(parseFloatFormatted(hind)* parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
});
var dok = document.getElementById("js-doksumma")
dok.innerText = totalAmount.toFixed(2)
}
</script>
but got error
How to properly implement this ? Should pure CSS, javascript or query used?
Modern Chrome browser is used in mobile phone, ASP.NET 6 MVC Razor application.
Solution 1:[1]
As Nick Vu said a first problem is in the for loop and I changed to:
for (let i = 0; i < table.rows.length; i++) {
I find more problems in the code for example the index of the childNodes is wrong, using
console.log(row.cells[1].childNodes)
you can see there are 3 child and you are searching for the middle one (index: 1)
Then for accessing the data of the input element you need to use the .value property like this:
const kogus = row.cells[2].childNodes[1].value
********************* EDIT *******************
Changing the code as the answer has changed.
For accessing the data of the html element use .innerHTML property.
function parseFloatFormatted(txt) {
if (typeof txt !== 'string' || txt === null || txt === "") {
return 0
}
return parseFloat(txt.replace(',', '.').replace(' ', ''))
}
function orderSumRefresh() {
let totalAmount = 0
const table = document.getElementById("order-products")
/*
for (let i = 0; i < table.rows.length; i++) {
const row = table.rows[i]
const hind = row.cells[1].childNodes[1].innerHTML
const kogus = row.cells[2].childNodes[1].value
const rowSum = Math.round(parseFloatFormatted(hind) * parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
}
*/
for (const row of table.rows) {
const hind = row.cells[1].querySelector(".mobileorder-price").innerHTML
const kogus = row.cells[2].querySelector(".quantity").value
const rowSum = Math.round(parseFloatFormatted(hind)* parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
}
const dok = document.getElementById("js-doksumma")
dok.innerText = totalAmount.toFixed(2)
}
<table id="order-products" class="mobileorder-table">
<colgroup>
<col style="width: 80%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>
Product1
</td>
<td>
<span class="mobileorder-price">0,98</span>
</td>
<td>
<input data-product="4750211645618" class="quantity" id="product_Soodkogus" name="product.Soodkogus"
type="number" min="0" max="999999" value="" onblur="orderSumRefresh()" />
</td>
</tr>
</tbody>
</table>
Order total <p id="js-doksumma"></p>
I suggest you to use the console.log() and log some variable to see if there is somethink wrong with the code.
Solution 2:[2]
Nick is correct. Remember that table.rows is not an array but an HTMLCollection. You can fix the issue simply doing:
const table = document.getElementById("order-products")
for (const row of Array.from(table.rows)) {
}
If you want to see for yourself that there is an "length" property being iterated over, open the dev tools, select the table from the elements tab, and run this snippet in the console:
for (let i in $0.rows) {
console.log(i);
console.log($0.rows[i].cells[0]);
}
You will see the last iteration print "length" and then throw an exception.
Solution 3:[3]
Your problem is from here
for (let i in table.rows) {}
The value will be "0" and "length" (not index like your expectation), so it throws an error while trying to access row.cells[0].childNodes (row.cells is undefined)
I'd suggest you modify it to
for (const row of table.rows) {}
The full code can be
function parseFloatFormatted(txt) {
if (typeof txt !== 'string' || txt === null || txt === "") {
return 0
}
return parseFloat(txt.replace(',', '.').replace(' ', ''))
}
function orderSumRefresh() {
let totalAmount = 0
const table = document.getElementById("order-products")
for (const row of table.rows) {
const hind = row.cells[1].childNodes[0].innerHTML
const kogus = row.cells[2].childNodes[0].innerText
const rowSum = Math.round(parseFloatFormatted(hind) * parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
}
const dok = document.getElementById("js-doksumma")
dok.innerText = totalAmount.toFixed(2)
}
<table id="order-products" class="mobileorder-table">
<colgroup>
<col style="width: 80%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>
Product1
</td>
<td>
<span class="mobileorder-price">0,98</span>
</td>
<td>
<input data-product="4750211645618" class="quantity" id="product_Soodkogus" name="product.Soodkogus" type="number" min="0" max="999999" value="" onblur="orderSumRefresh()" />
</td>
</tr>
</tbody>
</table>
Order total
<p id="js-doksumma"></p>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | smallnoyd |
| Solution 3 |
