Sum of the Filtered Rows - javascript

I have a table like this in my page:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<input type="text" id="myInput" placeholder="Search for anything.." title="Type in a name" ></input>
<table class="table table-bordered table-striped" >
<tbody id="myTable">
<td>
<?php echo $product_name ?>
</td>
<td>
<?php echo $gender ?>
</td>
<td>
<?php echo $date ?>
</td>
</td>
<td>
<?php echo $quantity ?>
</td>
<td>
<?php echo $shopname ?>
</td>
<td class="valor text-right">
<?php echo $price ?>
</td>
</tbody>
<tfoot>
<tr class="info">
<td colspan="2" class="text-right">TOTAL:</td>
<td class="total text-right"></td>
</tr>
</tfoot>
</table>
The idea here is to calculate the total for the column with class valor and it's shown on foot of the table at the colmn with class total.
And also the idea is that the user can filter rows typing anything on the input text named myInput and therefore the total should be recalculated.
By this time I'm able to filter rows with the jQuery code below:
$(document).ready(function () {
var $rows = $(".table tbody tr");
var total = 0;
$rows.each(function () {
total += parseFloat($(this).find(".valor").text().replace(/\./g, "").replace(",", "."));
});
$("#myInput").keyup(function () {
var filtertext = $(this).val();
var regex = new RegExp(filtertext, 'i');
$rows.hide().filter(function () {
return regex.test($(this).text());
}).show();
$(".table tbody tr:visible").each(function () {
total += parseFloat($(this).find(".valor").text().replace(/\./g, "").replace(",", "."));
});
$(".total").html(formataTotal(total.toFixed(2)));
});
$(".total").html(formataTotal(total.toFixed(2)));
});
function formatTotal(num) {
var parts = num.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
return parts.join(",");
}
By using the above code m successfully filtering the rows but i am not getting any sum of the column after being filtered rows nor the total sum of that column valor

A couple things to address to get the script functioning
You have defined formatTotal but you are calling formataTotal.
With that adjustment you should start seeing a total output.
You'll see a total but you now have a running total since you
have the variable total was defined in the global scope of the
script. This will persist until you refresh the browser. Reset your total when your keyup function begins.
$("#myInput").keyup(function () {
total = 0;
...
I would recommend to also break some of your code into smaller, reuseable functions. For example, when setting your total value create a function as such
function displayTotal(total) {
$(".total").html(formatTotal(total.toFixed(2)));
}
You can take that one step further and note that you use the same class consistently to output the total so you might want to offload that a global.
$totalElement = $(".total");
function displayTotal(total) {
$totalElement.html(formatTotal(total.toFixed(2)));
}
You should consider handling your total value consistently and with some precaution so you do not end up with a 'NaN' value. Again you can break the task of checking a row for a price with a function.
function getPriceForRow(row) {
$valor = $(row).find(".valor");
if($valor.length) {
return parseFloat($valor.text().replace(/\./g, "").replace(",", "."));
}
return parseFloat(0);
}
With a couple small adjustments your script may look as such. There are other improvements that can be made and things that you should ideally do in this case, but hopefully I gave a sense for what you can accomplish just with breaking your code down into solid functions.
$(document).ready(function () {
var $rows = $(".table tbody tr");
var $totalElement = $(".total");
var total = 0;
$rows.each(function () {
total += getPriceForRow(this);
});
displayTotal(total);
$("#myInput").keyup(function () {
total = 0;
var filtertext = $(this).val();
var regex = new RegExp(filtertext, 'i');
$rows.hide().filter(function () {
return regex.test($(this).text());
}).show();
$(".table tbody tr:visible").each(function () {
total += getPriceForRow(this);
});
displayTotal(total);
});
function getPriceForRow(row) {
$valor = $(row).find(".valor");
if ($valor.length) {
return parseFloat($valor.text().replace(/\./g, "").replace(",", "."));
}
return parseFloat(0);
}
function formatTotal(num) {
var parts = num.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
return parts.join(",");
}
function displayTotal(total) {
$totalElement.html(formatTotal(total.toFixed(2)));
}
});
Ideally you can avoid your globals in this case. You may want to read into closures here on MDN . It is how you can simulate private scope to an extent in your script. More or less, wrapping up and protecting the values in the contexts they are needed (simplification, I know).
Global scope variables are often troublesome for a number of reasons. You can do some reading on this here
Here is a good library for formatting currency as well, accounting.js

Related

tofixed(2) function apply to html class by name

The function is working correctly if simply var x (a digit)
but when I am trying to apply the same to html table class by name it is not working at all
<html>
<body>
<tr>
<td class="sal">45.515420</td>
</tr>
<script>
function myFunction() {
var sal = document.getElementsByClassName("sal");
for (i = 0; i < sal.length; i++) {
var currentValue = sal[i].innerHTML;
var newvalue = (sal.toFixed(2));
sal[i].innerHTML = newValue
}
}
onload = myFunction()
</script>
</body>
</html>
The provided code needs some changes, I'll try to address them:
Convert currentValue to number because toFixed is part of a Number
var currentValue = Number(sal[i].innerHTML);
onload = myFunction(), we can just call the function to run it on load
myFunction();
Wrapped <td class='sal'>45.515420</td> in a <table> to make the HTML valid
<table>
<tr>
<td class='sal'>45.515420</td>
</tr>
</table>
Applying those fixes gives:
function myFunction() {
var sal = document.getElementsByClassName("sal");
for (i = 0; i < sal.length; i++) {
var currentValue = Number(sal[i].innerHTML);
sal[i].innerHTML = currentValue.toFixed(2);
}
}
myFunction();
<table>
<tr>
<td class='sal'>45.515420</td>
</tr>
</table>
First, in order to use document.getElementsByClassName on td elements, you need to wrap your tr and td element inside table tag.
Second, toFixed() is a method for number and you need to convert the string to a number using Number() before you use toFixed().
var sal = document.getElementsByClassName("sal");
for (i = 0; i < sal.length; i++) {
var currentValue = sal[i].innerHTML;
var newValue = Number(currentValue).toFixed(2);
sal[i].innerHTML = newValue;
}
<html>
<body>
<table>
<tbody>
<tr>
<td class="sal">45.515420</td>
<td class="sal">49.515420</td>
</tr>
</tbody>
</table>
</body>
</html>
Along with all the other good advice, here's version that uses more modern JS practices.
querySelectorAll
forEach
Arrow function expressions
const sals = document.querySelectorAll('.sal');
sals.forEach(sal => {
const number = Number.parseFloat(sal.textContent);
sal.textContent = number.toFixed(2)
});
<table>
<tbody>
<tr>
<td class="sal">45.515420</td>
</tr>
</tbody>
</table>

How to create an array from the columns of a table in Javascript?

I have an HTML table like this:
SALES RENTS
ROME MILAN ROME MILAN MONEY
The HTML code is the following:
<TR>
<TD CLASS=HD1 COLSPAN=2>SALES</TD>
<TD CLASS=HD1 COLSPAN=2>RENTS</TD>
<TD CLASS=HDCOLSEP> </TD>
</TR>
<TR>
<TD>ROME</TD>
<TD>MILAN</TD>
<TD>ROME</TD>
<TD>MILAN</TD>
<TD>MONEY</TD>
</TR>
What I need, is to create with javascript an array like this:
(ROME-SALES, MILAN-SALES, ROME-RENTS, MILAN-RENTS, MONEY).
I have already created the array that contains the element of the first row.
Below you can find my code as it was in the past (At the beginning I needed just to take the elements of the first TR). Now I need to modify it and to create an array as specified before.
I don't know if it is clear from the table, but the first ROME and MILAN columns are referred to the column SALES, the second ROME and MILAN are referred to the RENTS column, while MONEY doesn't have any dependence.
Do you have any idea to do this?
Thanks in advance.
function getColumnsVal(id) {
var header = $("table#" + id + " thead tr:eq(1)");
var header_fields = $("td", header);
var header_vals = [];
header_fields.each(function(idx, val) {
var $$ = $(val);
header_vals.push($$.text());
});
return header_vals;
}
It is definitely possible to read values from the table cells. I edited the post a bit to illustrate the code.
I presume that HTML structure is rigid and you always have two rows of titles in the thead and somewhat random number of merged cells in the first row.
You’d want to match the number of columns in both rows, i.e. take the colspan number into account when traversing the cells.
Read both rows and generate strings by combining cell values in corresponding columns.
For example:
function readTableRow(row) {
var values = [];
$("td", row).each(function(index, field) {
var span = $(field).attr("colspan");
var val = $(field).text();
if (span && span > 1) {
for (var i = 0; i<span; i++ ) {
values.push(val);
}
} else {
values.push(val);
}
});
return values;
}
function getColumnsVal(id) {
// Read the first row, taking colspans into account
var first_row = $("table#" + id + " thead tr:eq(0)");
var first_row_vals = readTableRow(first_row);
// Read the second row, taking colspans into account
var second_row = $("table#" + id + " thead tr:eq(1)");
var second_row_vals = readTableRow(second_row);
if (first_row_vals.length != second_row_vals.length) {
return null;
}
var results = [];
for (var i = 0; i<first_row_vals.length; i++) {
results.push([first_row_vals[i].trim(), second_row_vals[i].trim()].filter(function (el) {return el}).join("-"));
}
return results;
}
function displayResults(results) {
var result = "RESULT: <br />";
results.forEach(function(r) {
result = result + r + "<br />";
});
$("#result").html(result);
}
displayResults(getColumnsVal("sample"));
JSFiddle:
https://jsfiddle.net/adanchenkov/n61dqfrs/

Reading text in columns from HTML tables

I've been debugging for some time, trying to get the value of a column in a table. I think once I've done this, it should be easy to pass the value in the next column out of my JS function.
My HTML table is:
<table id="country_LE_table" style = "display:none">
<tr>
<td>Japan</td>
<td>83.7</td>
</tr>
<tr>
<td>Switzerland</td>
<td>83.4</td>
</tr>
</table>
My Javascript is:
<script type="text/javascript">
function getLifeExpectancy() {
var Country = "<?php echo $Country ?>";
document.write(Country); // this gets read OK
var table = document.getElementById("country_LE_table");
var tr = table.getElementsByTagName("tr");
document.write(tr.length); document.write("<br>"); // works as expected
for (var i = 0; i < tr.length; i++) {
document.write(tr[i].innerHTML); document.write("<br>"); // works well up to here
// the following doesn't work
var td = tr[i].getElementsByTagName("td")[0];
if (td = Country) { //need td.fullHTML/value/fullText?
return tr[i].getElementsByTagName("td")[1]; // return the number
}
document.getElementById("demo").innerHTML = getLifeExpectancy();
</script>
If I do document.write(td), I get "[object HTMLTableCellElement]" on my page.
If I do document.write(td.fullHTML) I get "undefined" on my page.
When I explore other methods than td.innerHTML, I get this - it looks like I can't use functions based around text.
Use this instead. you have used assignment operator instead of comparison operator "=="
if (td.innerHTML == Country)
{
}

Getting and updating the right table html values with jquery

I have tried to get the solution on line but can't find one.
I will try and explain my problem because i can't make this in fiddle because the values are from the database.
I have two tables one displays data from the database.I have a button which when I click add it copy the contents of the first table and append them to the second table.
I am able to do it.
Now the issue am stuck is that i want to be able to check if i have added a data before in the second table and update the one that was added.
My jquery code here :
$('#centerElem tr').each(function(index, items){
$(this)find('input:checked')each(function(){
$this= $(this);
var chkItemcol = $this.parent().siblings('td');
var chklen = chkItemcol,length;
var chkItemValue = chkItemcol.eq(0).text(); var chkItemPrice = chkItemcol.eq(chklen-1).text();
var sumprice=0;
createrow ="<tr class='data'><td class='itemQty'>"+count+"</td>";
// iterate through the columns.
var mlen = chklen-1;
for(var i = 0; i<chklen; i++){ // add class to the item name
if(i == 0){
createrow += "<td class='name'>";
}else{
createrow += "<td>";
}
createrow += $this.parent().siblings('td').eq(i).text();
}
createrow += "</td>";
//alert(createrow);
createrow += "<td class='subtotal'></td></tr>";
if(i == (mlen)){
sumprice = ($this.parent().siblings('td').eq(0).text()) * ($this.parent().siblings('td').eq().text(mlen));
}
createTotal = "<tr><td>Total</td><td class='totalsum'>"+sumprice+"</td></tr>";
$('.ordertable .name').each(function (index, item) {
// get the checked <td>
var chkItemcol = $this.parent().siblings('td');
// get the checked row numbers of columns
var $item = $(item);
$data = $item.text();
var olen = $($item.siblings()).length;
var itemprice;
var subTotal
if ($data == chkItemValue) {
count++;
flag = true;
//get the item price
itemprice = $($item.siblings()[olen - 2]).text();
//multiple the qty with the item price
subTotal = count * itemprice;
// set the qty
$($item.siblings()[0]).text(count);
// set the subtotal.
$($item.siblings()[olen - 1]).text(subTotal);
return count;
} else {
count = 1;
itemprice = $($item.siblings()[olen - 2]).text();
alert("first add price " + itemprice);
subTotal = count * itemprice;
$($item.siblings()[olen - 1]).text(subTotal);
flag = false;
return count;
}
});
// check if the item was added to the ordered list table
if (flag) {
count++;
} else {
count = 1;
$(createrow).appendTo($('.ordertable > tbody'));
}
});
});
here is my html part, the table that display the database values.
<table><thead><tr><td><input type="checkbox" name="checkall"></td><td>Dish Name</td><td>Discription</td><td>ingredients</td><td>type</td><td>price</td></tr></thead>
<tbody>
<tr><td><input type="checkbox" name="chk" id="chk"/></td><td class='name'>Rice </td><td>white parboiled rice</td><td>rice</td><td>none</td><td>300</td></tr>
<tr><td><input type="checkbox" name="chk" id="chk"/></td><td class='name'>Beans </td><td>parboiled beans</td><td>beans an d salt/td><td>none</td><td>400</td></tr>
</tbody>
</table>
Here is the one i am appending the copied values to :
<TABLE class="ordertable" style="width:100%; border-collapse:collapse; border: solid 1px #000000">
<TBODY>
</TBODY><TFOOT></TFOOT></TABLE>
How can i do this ?
May I suggest a different approach? Put your data model in pure Javascript variables and use those for calculations etc. Only when done render the HTML. E.g.:
var products = {
rice: {name: 'Rice', description: 'White parboiled rice', price: 300},
beans: {name: 'Beans', description: 'Parboiled beans', price: 400}
};
var cart = {
rice: {quantity: 0, subtotal: 0},
beans: {quantity: 0, subtotal: 0}
};
This makes your life so much easier! Have a look at this jsFiddle
im not sure if this will solve much of what you're encountering. but there are some glaring typos in your html and jquery code. I have created a jsFiddle to make this easier for you to update.
watch for places where you're using , instead of . or forgetting . entirely in your js. Also make sure you're vigilant about closing your lines with ;. With your HTML you're doing well just looks like a typo in one of the closing </td>
I have added a list at the top of the JS section of the undeclared JS variables from your code that i guessed at.
heres the link: http://jsfiddle.net/6ryBL/3/
for templating of js you might want to have a look at creating javascript html templates using a templating language like EJS (http://embeddedjs.com/). Rather than 'building' the html piece by piece.
also added a 'check all' script thanks to https://stackoverflow.com/a/18537624/648350
EDIT: changed the JS to do what OP was asking for (would highly recommend a templating system and a localstorage/cookie solution to manage the cart data). Regardless, all cart data should be checked at server level before payment steps to confirm both stock and prices are correct.
http://jsfiddle.net/6ryBL/6/

Disregard a particular TD element

Below I have the code that allows me to edit a table row inline. However it edits ALL of the TDs within that row. My problem, along with the code, are stated below. Any help is appreciated.
<tbody>
<tr>
<th scope="row">Test</th>
<td class="amount">$124</td>
<td class="amount" id="" >$154</td>
<td class="diff">- 754</td>
</tr>
</tbody>
The above table is just a sample. What I have been trying to accomplish is, to simply edit the TDs within that particular row, but I need it to disregard the diff TD.
I'm fairly new to jQuery and have got the following code via the help of a jQuery book.
$(document).ready(function() {
TABLE.formwork('#current-expenses');
});
var TABLE = {};
TABLE.formwork = function(table){
var $tables = $(table);
$tables.each(function () {
var _table = $(this);
_table.find('thead tr').append($('<th class="edit"> </th>'));
_table.find('tbody tr').append($('<td class="edit"><input type="button" value="Edit"/></td>'))
});
$tables.find('.edit :button').live('click', function(e) {
TABLE.editable(this);
e.preventDefault();
});
}
TABLE.editable = function(button) {
var $button = $(button);
var $row = $button.parents('tbody tr');
var $cells = $row.children('td').not('.edit');
if($row.data('flag')) { // in edit mode, move back to table
// cell methods
$cells.each(function () {
var _cell = $(this);
_cell.html(_cell.find('input').val());
})
$row.data('flag',false);
$button.val('Edit');
}
else { // in table mode, move to edit mode
// cell methods
$cells.each(function() {
var _cell = $(this);
_cell.data('text', _cell.html()).html('');
if($('td.diff')){
var $input = $('<input type="text" />')
.val(_cell.data('text'))
.width(_cell.width() - 16);
_cell.append($input);
}
})
$row.data('flag', true);
$button.val('Save');
}
}
I have attempted to alter the code so that it would disregard the diff class TD, but have had no luck so far.
Replace
var $cells = $row.children('td').not('.edit');
with
var $cells = $row.children('td').not('.edit').not('.diff');
Add one more line after:
var $cells = $row.children('td').not('.edit').not('.diff');

Categories