jQuery Each Loop Not updating HTML in variable - javascript

I have a variable html that stores HTML:
<tr class="odd">
<td class="charge1">0</td>
<td class="nc1">0</td>
</tr>
<tr class="even">
<td class="charge2">0</td>
<td class="nc2">0</td>
</tr>
<tr class="odd">
<td class="charge3">250</td>
<td class="nc3">0</td>
</tr>
Basically I need to add the values for the td with the class starting with charge to the values for the td with the class starting with nc and replace the value in the td with class starting with nc with the sum. The values in both td's in each row could change, so the code needs to be dynamic. So for this example, the resulting HMTL in the variable should be:
<tr class="odd">
<td class="charge1">0</td>
<td class="nc1">0</td>
</tr>
<tr class="even">
<td class="charge2">0</td>
<td class="nc2">0</td>
</tr>
<tr class="odd">
<td class="charge3">250</td>
<td class="nc3">250</td>
</tr>
In this example, the only row that actually changes is the third row. The td starting with class nc now shows 250 instead of the original 0.
I have to use the variable html later in the code with the updated td information if it did change.
This is the code that I have, but it's not working:
var html = $('#chargetable').html();
console.log(html);
$('[class*=nc]', html).each(function(){
var ncamount = $(this).html();
var chargeamount = $(this).parents('tr').find('[class*=charge]').html();
var totalnc = parseFloat(chargeamount) + parseFloat(ncamount);
$(this).html(totalnc);
console.log(chargeamount + ' ' + ncamount + ' ' + totalnc);
});
console.log(html);
This is the results of the console's log:
<tr class="odd">
<td class="charge1">0</td>
<td class="nc1">0</td>
</tr>
<tr class="even">
<td class="charge2">0</td>
<td class="nc2">0</td>
</tr>
<tr class="odd">
<td class="charge3">250</td>
<td class="nc3">0</td>
</tr>
0 0 0
0 0 0
250 0 250
<tr class="odd">
<td class="charge1">0</td>
<td class="nc1">0</td>
</tr>
<tr class="even">
<td class="charge2">0</td>
<td class="nc2">0</td>
</tr>
<tr class="odd">
<td class="charge3">250</td>
<td class="nc3">0</td>
</tr>
The html variable isn't being updated, but I can't for the life of me figure out how to get it to update, short of splitting the variable, replacing the td with class nc, and recreating the html variable on each iteration. I'm thinking there's got to be a better way to do this.
Any help is very much appreciated.

The problem with you code is that you cannot use html variable in this line
$('[class*=nc]', html)
the second parameter is used to define scope in which jQuery searches for the selector.
So, like document,parent.document(if its iframe etc..)
If you need the original dom you can use jQuery .clone() to store the original dom like this
//if you require the original code for later clone it
var htmlclone = $('#chargetable').clone().html();
console.log(htmlclone);
$('#chargetable [class*=nc]').each(function(){
var ncamount = $(this).html();
var chargeamount = $(this).parents('tr').find('[class*=charge]').html();
var totalnc = parseFloat(chargeamount) + parseFloat(ncamount);
$(this).html(totalnc);
console.log(chargeamount + ' ' + ncamount + ' ' + totalnc);
});
console.log(htmlclone);
Here is a fiddle http://jsfiddle.net/z4n7kjcf/

$(function () {
var $chargeTable = $("#chargetable");
var $chargeTableCloned = $chargeTable.clone();
var $chargeTableRows = $("tr", $chargeTableCloned);
$.each($chargeTableRows, function(i, $tr){
var $tdCharge = $("td[class^='charge']", $tr);
var $tdNc = $("td[class^='nc']", $tr);
var charge = parseInt($tdCharge.text(), 10);
var nc = parseInt($tdNc.text(), 10);
$tdNc.text(charge + nc);
});
$chargeTable.after($chargeTableCloned);
});
Example

Related

Get column name from row mapping with onClick handler

In this reactjs app I have a table with the following body:
<tbody>
{results.map(result =>
<tr key={result.metric} onClick={this.handleClick}>
<td className="inpt-td">{result.t00}</td>
<td className="inpt-td">{result.t01}</td>
<td className="inpt-td">{result.t02}</td>
<td className="inpt-td">{result.t03}</td>
<td className="inpt-td">{result.t04}</td>
<td className="inpt-td">{result.t05}</td>
<td className="inpt-td">{result.t06}</td>
<td className="inpt-td">{result.t07}</td>
<td className="inpt-td">{result.t08}</td>
<td className="inpt-td">{result.t09}</td>
<td className="inpt-td">{result.t10}</td>
<td className="inpt-td">{result.t11}</td>
<td className="inpt-td">{result.t12}</td>
<td className="inpt-td">{result.t13}</td>
<td className="inpt-td">{result.t14}</td>
<td className="inpt-td">{result.t15}</td>
<td className="inpt-td">{result.t16}</td>
<td className="inpt-td">{result.t17}</td>
<td className="inpt-td">{result.t18}</td>
<td className="inpt-td">{result.t19}</td>
<td className="inpt-td">{result.t20}</td>
<td className="inpt-td">{result.t21}</td>
<td className="inpt-td">{result.t22}</td>
<td className="inpt-td">{result.t23}</td>
</tr>
)}
</tbody>
The header does not exist for this particular table, but I was wondering if there was a way to obtain the column name of a clicked cell. So for example if you clicked on the second cell in a given row, it would return "t01", which is the column name.
My searches online did not provide an efficient way of doing this. Is there a method to retrieve this info?
In your handleClick you can get access to the event.target property, which is a cell.
After that you can do:
var child = event.target;
var parent = child.parentNode;
// equivalent of parent.children.indexOf(child)
var index = Array.prototype.indexOf.call(parent.children, child);
var value = 't' + index // this will be value what you are looking for
If you need information how to use event.target - here is an example.

How to replace text of tds instead of href

i have a table with multiple rows. and i have rows that each of them has a specific class. in the last row i have a link . how can i replace each td text infront of their name in link ?
i wrote the below code but it sets the texts at the end of my links.
here is my snippet :
$(".list").each(function(index, element) {
var route=$(this).closest("tr").find(".route").text()
var airline=$(this).closest("tr").find(".airline").text()
var route=$(this).closest("tr").find(".route").text()
var linkk=$(this).attr("href")
$(this).attr("href",linkk+route+airline+route); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table border="1">
<tr>
<td class="route">tehran-istanbul</td>
<td class="airline">Iran air</td>
<td class="route">Ss 454</td>
<td><p class="date1">1398-5-12</p><p class="date2">(2017-08-23)</p></td>
<td>link</td>
</tr>
<tr>
<td class="route">tehran-Ankara</td>
<td class="airline">Tukish airline</td>
<td class="route">7547</td>
<td><p class="date1">1395-5-12</p><p class="date2">(2018-01-01)</p></td>
<td>link</td>
</tr>
</table>
few issues with your code:
you are redeclaring variable route, will not be helpful in your case, instead initialize two vars route1 and route2.
linkk+route+airline+route won't give the string you need you will need to add extra strings like 'route=' to identify parameters in between.
$(this).parents("tr").find(".route") will give you multiple elements with class route, you need to target specific elements, you can use first() and last() in your case.
$(".list").each(function(index, element) {
var route1= "route=" + $(this).parents("tr").find(".route").first().text();
var airline= "airline=" + $(this).parents("tr").find(".airline").first().text();
var route2= "route=" + $(this).parents("tr").find(".route").last().text();
var date1 = "date1=" + $(this).parents("tr").find(".date1").first().text();
var date2 = "date2=" + $(this).parents("tr").find(".date2").first().text();
var link = $(this).attr("href").replace(/\?.*/g, "?") + route1 + "&" + airline + "&" + route2 + "&" + date1 + "&" + date2;
$(this).attr("href", link);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table border="1">
<tr>
<td class="route">tehran-istanbul</td>
<td class="airline">Iran air</td>
<td class="route">Ss 454</td>
<td><p class="date1">1398-5-12</p><p class="date2">(2017-08-23)</p></td>
<td>link</td>
</tr>
<tr>
<td class="route">tehran-Ankara</td>
<td class="airline">Tukish airline</td>
<td class="route">7547</td>
<td><p class="date1">1395-5-12</p><p class="date2">(2018-01-01)</p></td>
<td>link</td>
</tr>
</table>
Similar to #DiJ I slightly changed the name of one of your arguments (the second route to routeno). And then I basically tried to reduce the code to the minimum, making it simpler at the same time.
$(".list").each(function(index, element) {
['route','airline','routeno'].forEach(function(i,o){console.log(i)});
$(this).closest("tr").find("td").each((i,o)=>{
if (vars.indexOf(o.className)>-1)
this.href+=o.className+'='+encodeURIComponent(o.innerHTML)+'&';
});
this.href+='date1=&date2=';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table border="1">
<tr>
<td class="route">tehran-istanbul</td>
<td class="airline">Iran air</td>
<td class="routeno">Ss 454</td>
<td><p class="date1">1398-5-12</p><p class="date2">(2017-08-23)</p></td>
<td>link</td>
</tr>
<tr>
<td class="route">tehran-Ankara</td>
<td class="airline">Tukish airline</td>
<td class="routeno">7547</td>
<td><p class="date1">1395-5-12</p><p class="date2">(2018-01-01)</p></td>
<td>link</td>
</tr>
</table>
You can do the same also without the indexOf() testing, like
$(".list").each(function(index, lnk) {
var $tr=$(lnk).closest("tr");
['route','airline','routeno'].forEach(function(col,i){
lnk.href+=encodeURIComponent($tr.find("td."+col).text())+'&'; });
lnk.href+='date1=&date2=';
});

Highlight multiple rows in several tables

I have a page with several rows containing information, made by several users. I'm looking for a way to highlight the all the users rows on mouseover.
This "Highlight multiple items on hover's condition" almost solved my problem, but since the classes or id's in my problem are dynamic from a database, and would contain an identifier from the DB and are unique each time. I have not been able to apply it.
Example code: https://jsfiddle.net/3cehoh78/
<table class="testtable">
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 1a</td>
<td class="cellclass">Sam</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 2a</td>
<td class="cellclass">Frodo</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 3a</td>
<td class="cellclass">Sam</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 4a</td>
<td class="cellclass">Legoman</td>
<td class="cellclass">data</td>
</tr>
</table>
<br>
<br>
<table class="testtable">
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 1b</td>
<td class="cellclass">Sauron</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 2b</td>
<td class="cellclass">Sam</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 3b</td>
<td class="cellclass">Sam</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 4b</td>
<td class="cellclass">Legoman</td>
<td class="cellclass">data</td>
</tr>
<tr id="uniqueIDthatcantbechanged">
<td class="cellclass">Line 5b</td>
<td class="cellclass">Frodo</td>
<td class="cellclass">data</td>
</tr>
</table>
In this example, I want all the rows with "Sam" to be highlighted on mouseover on one of them, so rows 1a,3a,2b,3b.
I was thinking of adding a class to all the Sam rows when generating the tables (Sam has a unique user ID), but how do I then change css that affects all the rows on mouseover (and not just one).
Please note that I cant pre-add css classes for all the unique userID's, this is just an example.
Here a solution with JQuery https://jsfiddle.net/3cehoh78/5
$(document).ready(function() {
$( "tr" ).hover(function() {
var search = $(this).find("td:eq(1)").text();
$( ".highlight" ).removeClass("highlight");
$("tr:contains('"+search+"')").addClass("highlight");
}); /* END HOVER */
}); // end document ready
Simple solution without using jQuery and co: https://jsfiddle.net/3cehoh78/3/
var rows = [].slice.call(document.querySelectorAll('.testtable tr'));
rows.forEach(function(row) {
row.addEventListener('mouseover', function() {
resetHighlighting();
var name = row.querySelector('td:nth-child(2)').textContent;
rows.forEach(function(r) {
if (r.querySelector('td:nth-child(2)').textContent === name) {
r.classList.add('highlighted');
}
});
});
});
function resetHighlighting() {
rows.forEach(function(row) {
row.classList.remove('highlighted');
});
}
Here's another way using vanilla-JavaScript.
var tds = document.querySelectorAll('td');
var highlight = function () {
// take this person's name from the 2nd cell
var name = this.parentNode.children[1].innerHTML;
// highlight cells with same name
tds.forEach(function (td) {
var tr = td.parentNode;
// compare other's person name with this person name
// highlight if there is a match
tr.classList.toggle('highlight', tr.children[1].innerHTML === name)
});
}
// attach an event listener to all cells
tds.forEach(function (td) {
td.onmouseover = highlight;
});
Demo

How to select the last cell from table which is not null, using JQuery

I have a table with following rows and cells:
<table id='table1'>
<tr id='row1'>
<th>index</th>
<th>Product</th>
<th>Description</th>
</tr>
<tr id='row2' name='row'>
<td name='index'>1</td>
<td name='product'>Apples</td>
<td name='description'>fruits</td>
</tr>
<tr id='row3' name='row'>
<td name='index'>2</td>
<td name='product'>Bananas</td>
<td name='description'>fruits</td>
</tr>
<tr id='row4' name='row'>
<td name='index'>3</td>
<td name='product'>Carrots</td>
<td name='description'>vegetables</td>
</tr>
<tr id='row5' name='row'>
<td name='index'></td>
<td name='product'></td>
<td name='description'></td>
</tr>
</table>
I need to select the value for the last td with name='index' which is not null. Anyone has any idea how can this be done.
Use the following selector :
$('td[name=index]:not(:empty):last')
For purely educational purposes, here is a non jQuery version:
function getLastNonEmptyCell(tableSelector) {
//Find parent table by selector
var table = document.querySelector(tableSelector)
//Return null if we can't find the table
if(!table){
return null;
}
var cells = table.querySelectorAll("td")
var lastNonEmptyCell = null;
//Iterate each cell in the table
//We can just overwrite lastNonEmptyCell since it's a synchronous operation and the return value will be the lowest item in the DOM
cells.forEach(function(cell) {
//!! is used so it's so if it is not null, undefined, "", 0, false
//This could be changed so it's just cell.innerText.trim() !== ""
if (!!cell.innerText) {
lastNonEmptyCell = cell;
}
})
return lastNonEmptyCell;
}
var cell = getLastNonEmptyCell("#table1")
Edit
As #squint suggested this can be done much more succintly:
function lastNonEmptyCell(tableSelector) {
//Since we want the last cell that has content, we get the last-child where it's not empty. This returns the last row.
var row = document.querySelectorAll(tableSelector + " td:not(:empty):last-child")
//Just grabbing the last cell using the index
return row[row.length - 1]
}

Sum associative array key values and group it by key

I have table as follows :
<table>
<thead>
<th>PRODUCT</th>
<th>QUANTITY</th>
<th>AREA</th>
<th>PRICE</th>
<th>TOTAL</th>
<tr>
<td id="name">SWEETS</td>
<td id="qty">10</td>
<td id="area">250</td>
<td id="price">16.50</td>
<td id="total">160.50</td>
</tr>
<tr>
<td id="name"">DRY FOODS</td>
<td id="qty">5</td>
<td id="area">100</td>
<td id="price">10.25</td>
<td id="total">51.25</td>
</tr>
<tr>
<td id="name">FRESH</td>
<td id="qty">20</td>
<td id="area">250</td>
<td id="price">5</td>
<td id="total">100</td>
</tr>
<tr>
<td id="name">MEAT</td>
<td id="qty">10</td>
<td id="area">250</td>
<td id="price">15</td>
<td id="total">150</td>
</tr>
<tr>
<td id="name">FROZEN</td>
<td id="qty">20</td>
<td id="area">300</td>
<td id="price">10</td>
<td id="total">200</td>
</tr>
</table>
So, I want to make an array like {area:total} then grouping array values based on area and sum area values.
Like :
AREA 250 : 410.5
AREA 100 : 51.25
AREA 300 : 200
I tried as follow which I got it array but I don't know how can I grouping the areas ( I used setInterval function because employees can remove or change the area values)
setInterval(function() {
var $row = $(this).closest("tr");
var sasData = [];
$row.each(function(i) {
var sasValue = parseFloat($row.find("#area").val());
var totValue = parseFloat($row.find("#total").val());
sasData.push({sas:sasValue, tot:totValue});
console.log(sasData);
});
function compressedArray(original) {
var compressed = [];
};
}, 1500)
Could you please show me the way how can we handle this issue?
This JSFiddle should solve your problem. I've also fixed your missing thead, your double quote in the DRY FOODS td, and changes id's to classes:
http://jsfiddle.net/Q9nrf/1/
var areas = {};
$("tr").each(function() {
var area = $(this).find("td.area").text();
if (area != "") {
var total = parseFloat($(this).find("td.total").text());
if (!areas.hasOwnProperty(area)) {
areas[area] = 0;
}
areas[area] += total;
}
});
console.log(areas);
You will need to change the id values to some other attribute, say class.
Loop over the rows (use the tbody element to skip the header) and collect values from the elements with the classes you're after. You will need to use an array to store them, as you can't order the properties of an object and each property must have a unique name.
id should be unique. so change <td id="area">250</td> to <td class="area">250</td>
then just call:
o = {};
$("td.area").each(function(){
key = o[$(this).text()];
if (!key) key = 0;
key += parseFloat( $(this).closest("tr").find(".total").text());
});
then you have on object contains key-value [key=area code, value=total]

Categories