how can i get sum of one columns rows? [duplicate] - javascript

I am trying to add Price from table column to a total.
I am having problem adding values such as 10.00 or 5.99. I am able to calculate prices with int values, but not with values 10.00 or 5.99, etc.
Here is what I have below.
var table = document.getElementById("myTable"),
sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
sumVal = sumVal + parseF(table.rows[i].cells[2].innerHTML);
}
document.getElementById("val").innerHTML = "SubTotal =" + sumVal;
console.log(sumVal);
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
</table>
<span id="val"></span>

You have three issues:
You are grabbing the wrong cell index, indices start at 0:
table.rows[i].cells[1]
You need to call the correct parse function:
parseFloat(table.rows[i].cells[1].innerHTML);
You need to format your output:
"SubTotal = $" + sumVal.toFixed(2);
Update: Added functionality for removing rows.
updateSubTotal(); // Initial call
function updateSubTotal() {
var table = document.getElementById("myTable");
let subTotal = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[1].innerHTML);
}, 0);
document.getElementById("val").innerHTML = "SubTotal = $" + subTotal.toFixed(2);
}
function onClickRemove(deleteButton) {
let row = deleteButton.parentElement.parentElement;
row.parentNode.removeChild(row);
updateSubTotal(); // Call after delete
}
#myTable td {
padding: 0.25em;
}
#val {
display: block;
margin-top: 0.5em;
}
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoodie</td>
<td class="count-me">15.00</td>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
</table>
<span id="val"></span>

You are accessing the incorrect array element and also need to use parseFloat
The cells array is zero-based so you need to use cells[1] to access the second column:
var table = document.getElementById("myTable"),
sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
sumVal = sumVal + parseFloat(table.rows[i].cells[1].innerHTML);
}
document.getElementById("val").innerHTML = "SubTotal =" + sumVal;
console.log(sumVal);
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
</table>
<span id="val"></span>

updateSubTotal(); // Initial call
function updateSubTotal() {
var table = document.getElementById("myTable");
let subTotal = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[1].innerHTML);
}, 0);
let subTotal2 = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[2].innerHTML);
}, 0);
document.getElementById("val").innerHTML = "SubTotal = $" + subTotal.toFixed(2);
document.getElementById("val1").innerHTML = subTotal2.toFixed(2);
}
function onClickRemove(deleteButton) {
let row = deleteButton.parentElement.parentElement;
row.parentNode.removeChild(row);
updateSubTotal(); // Call after delete
}
#myTable td {
padding: 0.25em;
}
#val {
display: block;
margin-top: 0.5em;
}
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>M2</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoodie</td>
<td class="count-me">15.00</td>
<td class="count-me">34.00</th>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td class="count-me">22.34</th>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
</table>
<span id="val"></span>
<span id="val1"></span>

var cell = document.getElementsByClassName("count-me");
var val = 0;
var i = 0;
while (cell[i] != undefined) {
val += parseFloat(cell[i].innerHTML);
i++;
} //end while
document.getElementById("val").innerHTML = parseFloat(val).toFixed(2);
console.log(parseFloat(val).toFixed(2));
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr id="">
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td>
<button onClick="myFunction()">Remove</button>
</td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td>
<button onClick="myFunction()">Remove</button>
</td>
</tr>
</table>
<span id="val"></span>

Related

Calculating Sum of table in HTML

In my web application, I have created table and assigned values for table from controller.
Here I want to show the total of column value Amount at the end of table.
So I have done this so far but It didn't show the total value.
var tds = document.getElementById('PayvouchDt').getElementsByTagName('td');
var sum = 0;
for (var i = 0; i < tds.length; i++) {
sum += parseInt(tds[i].cells[3].innerHTML);
}
document.getElementById('PayvouchDt').innerHTML += '<tr><td>' + sum + '</td><td>Total Value</td></tr>';
<table class="table table-striped" id="PayvouchDt">
<thead>
<tr>
<th>#</th>
<th>Description</th>
<th>Cost Center</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
#{int RowNo = 0;} #for (int i = 0; i
< Model.First().PaymentVouchDetails.Count; i++) { <tr>
<td>#{RowNo++;} #RowNo</td>
<td>#Html.DisplayFor(Model => Model.First().PaymentVouchDetails[i].Details)</td>
<td>#Html.DisplayFor(Model => Model.First().PaymentVouchDetails[i].CostCenter)</td>
<td class="count-me">Rs.#Html.DisplayFor(Model => Model.First().PaymentVouchDetails[i].Amount)</td>
</tr>
}
</tbody>
</table>
You need the rows. The cells do not have cells
Also an amount normally have decimals so we need them as floats instead of ints
var trs = document.getElementById('PayvouchDt').getElementsByTagName('tr');
var sum = 0;
for (var i = 0; i < trs.length; i++) {
sum += parseFloat(trs[i].cells[3].textContent);
}
document.getElementById('PayvouchDt').innerHTML += '<tr><td>' + sum.toFixed(2) + '</td><td>Total Value</td></tr>';
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Description</th>
<th>Cost Center</th>
<th>Amount</th>
</tr>
</thead>
<tbody id="PayvouchDt">
<tr>
<td>1</td>
<td>Details</td>
<td>Costcenter</td>
<td class="count-me">1.50</td>
</tr>
<tr>
<td>2</td>
<td>Details</td>
<td>Costcenter</td>
<td class="count-me">3.20</td>
</tr>
</tbody>
</table>
I suggest to use the tbody and a reduce on the converted textContent
const tds = document.querySelectorAll('#PayvouchDt tr td.count-me'); // or td:nth-child(4)
const sum = [...tds].map(td => +td.textContent).reduce((a, b) => a + b)
document.getElementById('PayvouchDt').innerHTML += `<tr><td>${sum.toFixed(2)}</td><td>Total Value</td></tr>`;
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Description</th>
<th>Cost Center</th>
<th>Amount</th>
</tr>
</thead>
<tbody id="PayvouchDt">
<tr>
<td>1</td>
<td>Details</td>
<td>Costcenter</td>
<td class="count-me">1.50</td>
</tr>
<tr>
<td>2</td>
<td>Details</td>
<td>Costcenter</td>
<td class="count-me">3.20</td>
</tr>
</tbody>
</table>
you can sum the elements of the array simply using the javascript [reduce method][1].
for example
const myArray = [{value: 1, name: 'john'}, {value: 2, name: 'doe'}, {value: 3, name: 'john'}, {value: 4, name: 'doe'}];
const v = myArray.reduce((tot, el) => tot + el.value, 0);
console.log(v)
you can take this snippet and adapt it to your need
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce?retiredLocale=it

Hide empty html table rows

Problem
I have a table with one or more empty rows. How to hide empty rows from the table?
For example
1 - John | Alfredo
2 - Mark | Zuck
3 - |
4 - Carl | Johnson
In this case, I'd like to delete the third row.
Step Tried
I found how to delete a specific row, what about deleting all the empty rows?
deleteEmptyRows();
function deleteEmptyRows() {
var myTable = document.getElementById("myTable")
var rowToDelete = 2;
myTable.deleteRow(rowToDelete)
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
</tbody>
</table>
This is how you can dynamically hide empty table rows with javascript.
deleteEmptyRows();
function checkIfCellsAreEmpty(row) {
var cells = row.cells;
var isCellEmpty = false;
for(var j = 0; j < cells.length; j++) {
if(cells[j].innerHTML !== '') {
return isCellEmpty;
}
}
return !isCellEmpty;
}
function deleteEmptyRows() {
var myTable = document.getElementById("myTable");
for(var i = 0; i < myTable.rows.length; i++) {
var isRowEmpty = checkIfCellsAreEmpty(myTable.rows[i]);
if (isRowEmpty) {
myTable.rows[i].style.display = "none";
}
}
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
</tbody>
</table>
Here, a simple method for row is empty (this allows us to check for other conditions easily later).
Loop over rows and call remove if empty.
const rowIsEmpty = (tr) => Array.from(tr.querySelectorAll('td')).every(td => td.innerText === "");
deleteEmptyRows();
function deleteEmptyRows() {
var myTable = document.getElementById("myTable");
myTable.querySelectorAll('tr').forEach(tr => {
if(rowIsEmpty(tr)) tr.remove();
});
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Was answered in another thread.
Jquery: hiding empty table rows
Loops through all table tr rows, and checks td lengths. If the td length is empty will hide.
$("table tr").each(function() {
let cell = $.trim($(this).find('td').text());
if (cell.length == 0){
console.log('Empty cell');
$(this).addClass('nodisplay');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td>
</tr>
<tr>
<!-- Will hide --> <td></td>
</tr>
</table>
With native Javascript:
function removeRow(src) {
var tableRows = document.getElementById(src).querySelectorAll('tr');
tableRows.forEach(function(row){
if((/^\s*$/).test(row.innerText)){
row.parentNode.removeChild(row);
}
});
}
removeRow('myTable');
The only problem is when you have some other characters in the row, except the whitespaces. This regex checks for blank characters, but if u have a dot inside or any other non empty character, it will fail.

Retrieve a specific column / POSTCODE

I'm trying to only retrieve the POSTCODE field in this script.
Is there a way to only return this value?
<script>
function LookuptableWend(query) {
var tr = document.getElementsByTagName("tr"),y=0;
for (i = 0; i < tr.length; i++) {
if((y<25)&&(query)&&(tr[i].innerHTML.search(query)>-1)){
tr[i].className="found";y+=1;
}
else{tr[i].className="";
}
}
}
</script>
<table class="lookuptable" >
<tbody>
<tr>
<td>0097040K</td>
<td>Hospital Name 1</td>
<td>2/70 Kent Street</td>
<td>Block 1 </td>
<td>DEAKIN</td>
<td>ACT</td>
<td>2600</td>
<td>02 6232 4793</td>
</tr>
<script>LookuptableWend(document.getElementById("search").value);</script>
You could use querySelectorAll with nth-child (comments in js below)
function LookuptableWend(query) {
var td = document.querySelectorAll(".lookuptable td:nth-child(7)"); // get all postcode cells
for (i = 0; i < td.length; i++) {
if (td[i].innerHTML.search(query) != -1) { // search them for your query string
td[i].parentNode.className = "found"; // add a class to the row
} else {
td[i].parentNode.className = "";
}
}
}
LookuptableWend(2600);
.found {
background: green;
}
<table class="lookuptable">
<tbody>
<tr>
<td>0097040K</td>
<td>Hospital Name 1</td>
<td>2/70 Kent Street</td>
<td>Block 1 </td>
<td>DEAKIN</td>
<td>ACT</td>
<td>2600</td>
<td>02 6232 4793</td>
</tr>
<tr>
<td>0097040K</td>
<td>Hospital Name 1</td>
<td>2/70 Kent Street</td>
<td>Block 1 </td>
<td>DEAKIN</td>
<td>ACT</td>
<td>2601</td>
<td>02 6232 4793</td>
</tr>
<tr>
<td>0097040K</td>
<td>Hospital Name 1</td>
<td>2/70 Kent Street</td>
<td>Block 1 </td>
<td>DEAKIN</td>
<td>ACT</td>
<td>2600</td>
<td>02 6232 4793</td>
</tr>
</tbody>
</table>

Javascript How to deal with NaNs when adding and averaging values in a table

I'm trying to write an efficient javascript function that will loop through a table, grab all numbers, and ignore all tds with strings. The columns will be added and averaged, and rows will be appended for each.
I have the basic functionality for this working. Whereas, if the table does not include a string, the results are as expected. When the table does include a string, the total and average of the column are way off and I'm not exactly sure how the answer is being calculated. I'm hoping somebody can help me figure out a way to ignore these values all together, and create a more efficient way of writing this function.
Finally, I want to be able to call this function by simply passing in the table, e.g. buildRows(table);
Here's what I got so far:
// function to build total and average rows
function buildRow($element) {
var result = [];
$($element).find('tbody tr').each(function() {
// Ignore the first column reserved for labels
$('td:not(:first)', this).each(function(index, val) {
if (!result[index]) result[index] = 0;
result[index] += parseInt($(val).text());
});
});
// Get the total amount rows
var rowCount = $($element).find('tbody tr').length;
// Add Average Row
$($element).append('<tr class="avg-row"></tr>');
$($element).find('tr').last().append('<td>' + 'Averages' + '</td>');
$(result).each(function() {
$($element).find('tr').last().append('<td class="avg-td">' + this / rowCount + '</td>');
});
// Add Total Row
$($element).append('<tr class="total-row"></tr>');
$($element).find('tr').last().append('<td>' + 'Totals' + '</td>');
$(result).each(function() {
$($element).find('tr').last().append('<td class="total-td">' + this + '</td>');
});
}
// ideal function calls
var tableOne = $('.tableOne');
buildRow(tableOne);
var tableTwo = $('.tableTwo');
buildRow(tableTwo);
table {
border: 1px solid #333;
padding: 10px;
margin-right: 5px;
}
table tr:nth-child(odd) {
background-color: #e0e0e0;
}
table td {
padding: 10px;
border: 1px solid #555;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tableOne">
<tr>
<td>Row One</td>
<td>45</td>
<td>23.356</td>
<td>88</td>
</tr>
<tr>
<td>Row Two</td>
<td>111440.568</td>
<td>115555</td>
<td>4.21598</td>
</tr>
<tr>
<td>Row Three</td>
<td>27</td>
<td>42</td>
<td>144487.11</td>
</tr>
<tr>
<td>Row Four</td>
<td>23.356</td>
<td>125%</td>
<td>778978523.36</td>
</tr>
</table>
<table class="tableTwo">
<tr>
<td>Row One</td>
<td>45</td>
<td>23.356</td>
<td>Hello</td>
</tr>
<tr>
<td>Row Two</td>
<td>111440.568</td>
<td>115555</td>
<td>4.21598</td>
</tr>
<tr>
<td>Row Three</td>
<td>Dog</td>
<td>true</td>
<td>144487.11</td>
</tr>
<tr>
<td>Row Four</td>
<td>23.356</td>
<td>125%</td>
<td>778978523.36</td>
</tr>
</table>
The first table with no strings seems okay, 2nd table the results are way off and I'm not sure how the totals are being calculated.
You cannot just do parseInt on every value, it sometimes transform a string to a weird number. You have to check if it is not a valid number before you sum it up. I think of a regex or something like that, untested.
var v = $(val).text();
if(v.match(/^[\s0-9\.]+$/)){}
You need to check whether td value has integer or not by using var reg = /^\d+$/;
Since your using jQuery why not just use jQuery's built in is numeric condition check function $.isNumeric which will parse out pretty much all the data you don't want.
// true (numeric)
$.isNumeric( "-10" )
$.isNumeric( "0" )
$.isNumeric( 0xFF )
$.isNumeric( "0xFF" )
$.isNumeric( "8e5" )
$.isNumeric( "3.1415" )
$.isNumeric( +10 )
$.isNumeric( 0144 )
// false (non-numeric)
$.isNumeric( "-0x42" )
$.isNumeric( "7.2acdgs" )
$.isNumeric( "" )
$.isNumeric( {} )
$.isNumeric( NaN )
$.isNumeric( null )
$.isNumeric( true )
$.isNumeric( Infinity )
$.isNumeric( undefined )
Source: https://api.jquery.com/jQuery.isNumeric/
Example: https://jsfiddle.net/1d9Lbnp1/1/
You could just ignore the Nans and use Number instead of parseInt if you want something more accurate:
$('td:not(:first)', this).each(function(index, val) {
if (!result[index]) result[index] = 0;
var num = Number($(val).text());
num = isNaN(num) ? 0 : num;
result[index] += num;
});
Two things to remember:
parseFloat will capture floats and integers
When working with numbers, you can use the ||0 to hack ignore the falsy values, replacing them with a 0
Other than that, I took some liberties with your code, putting the necessary elements in variables:
// function to build total and average rows
function buildRow($table) {
var result = [],
$tbody = $table.find('tbody'),
$rows = $tbody.find('tr'),
row_count = $rows.length;
$rows.each(function() {
// Ignore the first column reserved for labels
var $cells = $('td:not(:first)',this);
$cells.each(function(index,cell) {
if (!result[index])
result[index] = 0;
result[index] += parseFloat($(cell).text()||0);
});
});
// Add Average Row
var $avg_row = $('<tr class="avg-row"></tr>');
$avg_row.append('<td>Averages</td>');
$.each(result,function() {
$avg_row.append('<td class="avg-td">' + ( this / row_count ) + '</td>');
});
$tbody.append($avg_row);
// Add Total Row
var $total_row = $('<tr class="total-row"></tr>');
$total_row.append('<td>Totals</td>');
$.each(result,function() {
$total_row.append('<td class="total-td">' + this + '</td>');
});
$tbody.append($total_row);
}
// ideal function calls
var $tableOne = $('.tableOne');
buildRow($tableOne);
var $tableTwo = $('.tableTwo');
buildRow($tableTwo);
table {
border: 1px solid #333;
padding: 10px;
margin-right: 5px;
}
table tr:nth-child(odd) {
background-color: #e0e0e0;
}
table td {
padding: 10px;
border: 1px solid #555;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tableOne">
<tr>
<td>Row One</td>
<td>45</td>
<td>23.356</td>
<td>88</td>
</tr>
<tr>
<td>Row Two</td>
<td>111440.568</td>
<td>115555</td>
<td>4.21598</td>
</tr>
<tr>
<td>Row Three</td>
<td>27</td>
<td>42</td>
<td>144487.11</td>
</tr>
<tr>
<td>Row Four</td>
<td>23.356</td>
<td>125%</td>
<td>778978523.36</td>
</tr>
</table>
<table class="tableTwo">
<tr>
<td>Row One</td>
<td>45</td>
<td>23.356</td>
<td>Hello</td>
</tr>
<tr>
<td>Row Two</td>
<td>111440.568</td>
<td>115555</td>
<td>4.21598</td>
</tr>
<tr>
<td>Row Three</td>
<td>Dog</td>
<td>true</td>
<td>144487.11</td>
</tr>
<tr>
<td>Row Four</td>
<td>23.356</td>
<td>125%</td>
<td>778978523.36</td>
</tr>
</table>
Here's another way to do the same thing, by retrieving the values first by column (using nth-child) and then using reduce to calculate sums:
['.tableOne', '.tableTwo'].forEach(function(tbl){
makeAggregates($(tbl));
});
function makeAggregates($tbl) {
var $tbody = $tbl.find('tbody');
var sums = sumOfColumns($tbody);
var $total_row = $('<tr class="total-row"><td class="total-td">Total</td></tr>');
var $average_row = $('<tr class="avg-row"><td class="avg-td">Averages</td></tr>');
$.each(sums, function(key,col) {
var total = col[1],
items = col[0];
$total_row.append('<td class="total-row">' + total + '</td>');
$average_row.append('<td class="avg-row">' + total / items + '</td>');
});
$tbody.append($average_row,$total_row);
}
function sumOfColumns($tbody) {
var $rows = $tbody.find('tr');
// Get number of columns
var num_cols = $rows.first().find('td').length;
var col_sums = {};
for (var col = 2; col < num_cols + 1; col++) {
var $col_data = $tbody.find('td:nth-child(' + col + ')'),
arr_values = $col_data.map(function() {
return this.textContent
}).get();
col_sums[col - 1] = [
arr_values.length,
arr_values.reduce(function(pv, cv) {
return pv + (parseFloat(cv) || 0)
}, 0)
];
}
return col_sums;
}
table {
border: 1px solid #333;
padding: 10px;
margin-right: 5px;
}
table tr:nth-child(odd) {
background-color: #e0e0e0;
}
table td {
padding: 10px;
border: 1px solid #555;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tableOne">
<tr>
<td>Row One</td>
<td>45</td>
<td>23.356</td>
<td>88</td>
</tr>
<tr>
<td>Row Two</td>
<td>111440.568</td>
<td>115555</td>
<td>4.21598</td>
</tr>
<tr>
<td>Row Three</td>
<td>27</td>
<td>42</td>
<td>144487.11</td>
</tr>
<tr>
<td>Row Four</td>
<td>23.356</td>
<td>125%</td>
<td>778978523.36</td>
</tr>
</table>
<table class="tableTwo">
<tr>
<td>Row One</td>
<td>45</td>
<td>23.356</td>
<td>Hello</td>
</tr>
<tr>
<td>Row Two</td>
<td>111440.568</td>
<td>115555</td>
<td>4.21598</td>
</tr>
<tr>
<td>Row Three</td>
<td>Dog</td>
<td>true</td>
<td>144487.11</td>
</tr>
<tr>
<td>Row Four</td>
<td>23.356</td>
<td>125%</td>
<td>778978523.36</td>
</tr>
</table>
As others have mentioned, the trick is to check if the value is a number before using it in your calculations. That's as easy as isNaN(parseInt(string)).
Overall I think you can simplify your code a lot by extracting the (good) data from the table into arrays of numbers (one array for each column). You can see that in the getData function in the below snippet. Then it's a simple matter of iterating over each column's data to calculate its total and average.
You can also simplify things by using semantic markup: <tbody> for your data, <th> for heading cells, and <tfoot> for the Averages and Totals rows. This makes both extracting the data and styling the output much easier.
Here's how it looks with jQuery. Mind you, my jQuery's a bit rusty. At the end of the post you'll find another snippet sans jQuery, which is only slightly more verbose.
jQuery
function getData($rows) {
return $('td', $rows[0]).toArray().map((_, idx) =>
$rows.toArray().reduce((result, row) => {
const value = parseInt($('td', row)[idx].innerText, 10);
return result.concat(isNaN(value) ? [] : value);
}, [])
);
}
function generateRow(label, values, precision=3) {
const mult = Math.pow(10, precision);
return $(`<tr><th>${label}</th></tr>`).append(
values.map(val => $(`<td>${Math.round(val * mult) / mult}</td>`)));
}
function aggregateData($table) {
const averages = [];
const totals = [];
getData($table.find('tbody tr')).forEach(values => {
const total = values.reduce((total, val) => (total + val), 0);
totals.push(total);
averages.push(total / values.length);
});
$('<tfoot>').append(
generateRow('Averages', averages),
generateRow('Totals', totals)
).appendTo($table)
}
aggregateData($('.tableOne'));
aggregateData($('.tableTwo'));
table { width: 300px; margin-bottom: 1em; border: 1px solid gray; }
tbody tr:nth-child(odd) { background-color: #e0e0e0; }
td, th { padding: 7px; text-align: center; }
tfoot tr { background-color: paleturquoise; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tableOne">
<tbody>
<tr>
<th>One</th>
<td>10</td>
<td>300</td>
<td>6000</td>
</tr>
<tr>
<th>Two</th>
<td>20</td>
<td>400</td>
<td>7000</td>
</tr>
<tr>
<th>Three</th>
<td>30</td>
<td>500</td>
<td>8000</td>
</tr>
<tr>
<th>Four</th>
<td>40</td>
<td>600</td>
<td>9000</td>
</tr>
</tbody>
</table>
<table class="tableTwo">
<tr>
<th>One</th>
<td>10</td>
<td>300</td>
<td>Hello</td>
</tr>
<tr>
<th>Two</th>
<td>20</td>
<td>400</td>
<td>7000</td>
</tr>
<tr>
<th>Three</th>
<td>Dog</td>
<td>true</td>
<td>8000</td>
</tr>
<tr>
<th>Four</th>
<td>40</td>
<td>600</td>
<td>9000</td>
</tr>
</table>
No jQuery
function getData(rows) {
const numCols = rows[0].querySelectorAll('td').length;
return new Array(numCols).fill().map((_, idx) =>
Array.prototype.reduce.call(rows, (result, row) => {
const value = parseInt(row.querySelectorAll('td')[idx].innerText, 10);
return result.concat(isNaN(value) ? [] : value);
}, [])
);
}
function generateRow(label, values, precision=3) {
const mult = Math.pow(10, precision);
const row = document.createElement('tr');
row.innerHTML = values.reduce((html, val) => html + `<td>${Math.round(val * mult) / mult}</td>`, `<th>${label}</th>`);
return row;
}
function aggregateData(table) {
const totals = [];
const averages = [];
getData(table.querySelectorAll('tbody tr')).forEach(values => {
const total = values.reduce((total, val) => (total + val), 0);
totals.push(total);
averages.push(total / values.length);
});
const tfoot = document.createElement('tfoot');
tfoot.appendChild(generateRow('Averages', averages));
tfoot.appendChild(generateRow('Totals', totals));;
table.appendChild(tfoot);
}
aggregateData(document.querySelector('.tableOne'));
aggregateData(document.querySelector('.tableTwo'));
table { width: 300px; margin-bottom: 1em; border: 1px solid gray; }
tbody tr:nth-child(odd) { background-color: #e0e0e0; }
td, th { padding: 7px; text-align: center; }
tfoot tr { background-color: paleturquoise; }
<table class="tableOne">
<tbody>
<tr>
<th>One</th>
<td>10</td>
<td>300</td>
<td>6000</td>
</tr>
<tr>
<th>Two</th>
<td>20</td>
<td>400</td>
<td>7000</td>
</tr>
<tr>
<th>Three</th>
<td>30</td>
<td>500</td>
<td>8000</td>
</tr>
<tr>
<th>Four</th>
<td>40</td>
<td>600</td>
<td>9000</td>
</tr>
</tbody>
</table>
<table class="tableTwo">
<tr>
<th>One</th>
<td>10</td>
<td>300</td>
<td>Hello</td>
</tr>
<tr>
<th>Two</th>
<td>20</td>
<td>400</td>
<td>7000</td>
</tr>
<tr>
<th>Three</th>
<td>Dog</td>
<td>true</td>
<td>8000</td>
</tr>
<tr>
<th>Four</th>
<td>40</td>
<td>600</td>
<td>9000</td>
</tr>
</table>

How To Sum All Table Rows td (TotalPrice) using td id Jquery

I am adding values to table like:
Item,Quantity,Price,TotalPrice
Now there are multiple rows: How can i sum TotalPrice of all to get GrandTotal using Jquery.
Code:
$("#Product").append(" <tr><td id='clientname'>" +ClientName+ "</td> <td id='item'>"+ItemName+"</td> <td id='quantity'>"+Quantity+"</td> <td id='price'>"+Price+"</td> <td id='totalprice'>"+TotalPrice+"</td> <td> <a onClick='deleteRow(this);'>Delete</a> </td> </tr>");
Its possible when i insert new row data its show grand total in textbox/label,Like:
function TotalPriceCalc()
{
var lblTotalPrice = document.getElementById('lblTotalPrice');
lblTotalPrice.value = sum;
}
Here's an example that will sum whatever column index you provide.
$(function() {
$("#subtotal").html(sumColumn(4));
$("#total").html(sumColumn(5));
});
function sumColumn(index) {
var total = 0;
$("td:nth-child(" + index + ")").each(function() {
total += parseInt($(this).text(), 10) || 0;
});
return total;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table style="border-spacing: 10px;">
<tr>
<td>ClientName</td>
<td>ItemName</td>
<td>Quantity</td>
<td>12</td>
<td>34</td>
</tr>
<tr>
<td>ClientName</td>
<td>ItemName</td>
<td>Quantity</td>
<td>56</td>
<td>78</td>
</tr>
<tr>
<td>ClientName</td>
<td>ItemName</td>
<td>Quantity</td>
<td>90</td>
<td>12</td>
</tr>
<tr>
<td colspan="3">Totals</td>
<td id="subtotal"></td>
<td id="total"></td>
</tr>
</table>
After you use class= instead of id= .Cause ID MUST be unique. you need to loop through each row and find totalPrice
$(document).ready(function(){
var TotalValue = 0;
$("#Product tr").each(function(){
TotalValue += parseFloat($(this).find('.totalprice').text());
});
alert(TotalValue);
});
While you tagged Jquery .. This is a Jquery solution so please be sure to include Jquery
You should use classes, not IDs, to name repeated elements. So it should be:
...<td class="totalprice">'+TotalPrice+'</td>...
Then you can do
function TotalPriceCalc() {
var total = 0;
$(".totalprice").each(function() {
total += parseFloat($(this).text());
});
$("#lblTotalPrice").val(total);
}
Have look, this is our table
<table class="table table-bordered">
<thead>
<tr>
<th>1</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td id="loop">50</td>
</tr>
<tr>
<td>1</td>
<td id="loop">60</td>
</tr>
<tr>
<td>1</td>
<td id="loop">70</td>
</tr>
</tbody>
<tbody>
<tr>
<td class="text-right">Total</td>
<td></td>
</tr>
</tbody>
And this is loop to have sum of price
$(function() {
var TotalValue = 0;
$("tr #loop").each(function(index,value){
currentRow = parseFloat($(this).text());
TotalValue += currentRow
});
console.log(TotalValue);
});

Categories