Compare two cells in a html table and highlight row if different - javascript

I have an HTML table (tree table precisely but it doesn't matter) and it has several columns. For each row, it is very important that the values in one of the columns should be higher than the other column. If that is not the case then I'd like to highlight that entire row. How do I do that?
My HTML code looks like this:
<table id="stepstats-list-exp">
<thead>
<tr>
<th> name </th>
<th> elp_01 </th>
<th> elp_20 </th>
<th> scal </th>
</tr>
</thead>
<tbody>
<tr data-tt-id=864845 data-tt-parent-id=>
<td> 'Init' </td>
<td class="elp_01"> 0 </td>
<td class="elp_20"> 0 </td>
<td class="scal"> 0.00 </td>
</tr>
<tr data-tt-id=864846 data-tt-parent-id=864845>
<td> 'Update' </td>
<td class="elp_01"> 0 </td>
<td class="elp_20"> 0 </td>
<td class="scal"> 0.00 </td>
</tr>
<tr data-tt-id=864847 data-tt-parent-id=>
<td> 'Load' </td>
<td class="elp_01"> 32 </td>
<td class="elp_20"> 31 </td>
<td class="scal"> 1.03 </td>
</tr>
</tbody>
</table>
In all my test cases, elp_20 should always be smaller than elp_01. If not, the entire row needs to be highlighted. For that purpose, I have this jQuery code that doesn't seem to be working. For each tr row, I'm checking each td column and comparing values.
<script type="text/javascript">
/* Highlight row if elp_20 > elp_01 */
$(document).ready(function () {
$("#stepstats-list-exp tr").each(function () {
$(this).find('td').each(function(){
if (parseInt($(".elp_20").text(), 10) < parseInt($(".elp_01").text(), 10)) {
$(this).parent("tr").css('background-color', 'crimson');
$(this).parent("tr").css('font-weight','bold');
$(this).parent("tr").css('color','white');
}
});
});
});
</script>

This working snippet accesses the table rows as an html collection that can be looped through to compare the values represented by the contents of the second and third cell of each row. An inline style attribute it used to highlight the row (alternative styling could be made by adding or toggling class names if something more complex is needed)
let tableRows = document.getElementById("stepstats-list-exp").getElementsByTagName('tr');
for (let i=0; i<tableRows.length; i++)
if (Number(tableRows[i].children[2].innerText) >= Number(tableRows[i].children[1].innerText)) {
tableRows[i].setAttribute("style", "background: yellow");
}
<table id="stepstats-list-exp">
<thead>
<tr>
<th> name </th>
<th> elp_01 </th>
<th> elp_20 </th>
<th> scal </th>
</tr>
</thead>
<tbody>
<tr data-tt-id=864845 data-tt-parent-id=>
<td> 'Init' </td>
<td class="elp_01"> 0 </td>
<td class="elp_20"> 0 </td>
<td class="scal"> 0.00 </td>
</tr>
<tr data-tt-id=864846 data-tt-parent-id=864845>
<td> 'Update' </td>
<td class="elp_01"> 0 </td>
<td class="elp_20"> 0 </td>
<td class="scal"> 0.00 </td>
</tr>
<tr data-tt-id=864847 data-tt-parent-id=>
<td> 'Load' </td>
<td class="elp_01"> 32 </td>
<td class="elp_20"> 31 </td>
<td class="scal"> 1.03 </td>
</tr>
</tbody>
</table>

You can just iterate through the classes, add them to a variable and iterate with a for loop, if you need to iterate one elp_01 to all elp_20 just map it.
Here's an example:
let firstColumn = document.getElementsByClassName('elp_01').innerText
let secondColumn = document.getElementsByClassName('elp_20').innerText
for (let i = 0; i < firstColumn.length; i ++) {
if (firstColumn[i] > secondColumn[i]) {
// Something - maybe add a class in css to color the row and add it to the element
}
else {
// Something else
}
}

Related

Jquery - simple multiplication assignment mistake

https://jsfiddle.net/ohrgw29y/#&togetherjs=4USeqx1oCx
I'm trying to make a column "price together" each cell in which would display two other cells of a row multiplied. I got it to "add assign" but cannot "multiply assign.
$(document).ready(function() {
$('tr').each(function() {
var price_row_total=0
$(this).find('.subjects').each(function() {
var price_attributes=$(this).text();
if(price_attributes.lenght!==0) {
price_row_total+=parseFloat(price_attributes);
}
});
$(this).find('#price_row_total').html(price_row_total);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="table_id">
<thead>
<tr>
<th scope="col">Supply</th>
<th scope="col">Used by</th>
<th scope="col">Periodicity</th>
<th scope="col">Amount</th>
<th scope="col">Units</th>
<th scope="col">Price per unit</th>
<th scope="col">Price together</th>
</tr>
</thead>
<tbody>
<tr>
<td>water</td>
<td>
<span>plant1</span>
</td>
<td>
<h4><b> monthly </b></h4>
</td>
<td class="subjects">
10
</td>
<td> <h4> liters </h4> </td>
<td class="subjects">
2.99
</td>
<td id="price_row_total"></td>
</tr>
<tr>
<td>hay</td>
<td>
<span>animal1</span>
</td>
<td>
<h4><b> one time </b></h4>
</td>
<td class="subjects">
15
</td>
<td> <h4> stacks </h4> </td>
<td class="subjects">
1.50
</td>
<td id="price_row_total"></td>
</tr>
</tbody>
</table>
P.S. I'm not even a beginner in JS , I have no idea what I'm doing, sorry. I'm sure it's simplest thing ever but I'm too short on time to learn JS synthax right now. Trying to finish this volunteered project for an animal sanctuary. Hope this explains why someone posts such simple things.
By no means is this answer elegant or even best practice, but it addresses you're current issue.
$(document).ready(function() {
$('tr').each(function() {
// this was modified to get price and unit based off class name (changed from subjects)
const unit = Number($(this).find('.units').text());
const price = Number($(this).find('.price').text());
// the toFixed(2) rounds to 2 decimal places as these are floating point numbers you will end up with something like 29.90000002
const price_row_total = (unit * price).toFixed(2);
$(this).find('.total').html(price_row_total);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="table_id">
<thead>
<tr>
<th scope="col">Supply</th>
<th scope="col">Used by</th>
<th scope="col">Periodicity</th>
<th scope="col">Amount</th>
<th scope="col">Units</th>
<th scope="col">Price per unit</th>
<th scope="col">Price together</th>
</tr>
</thead>
<tbody>
<tr>
<td>water</td>
<td>
<span>plant1</span>
</td>
<td>
<h4><b> monthly </b></h4>
</td>
<td class="units">
10
</td>
<td> <h4> liters </h4> </td>
<td class="price">
2.99
</td>
<td class="total"></td>
</tr>
<tr>
<td>hay</td>
<td>
<span>animal1</span>
</td>
<td>
<h4><b> one time </b></h4>
</td>
<td class="units">
15
</td>
<td> <h4> stacks </h4> </td>
<td class="price">
1.50
</td>
<td class="total"></td>
</tr>
</tbody>
</table>

How to sort only some rows of a table?

I have a following table:
And I want to sort the rows with names and ages with their articles -> My JavaScript code for sorting looks like this:
Right now it sorts the names and articles weirdly together.
My idea was somehow connect the nested rows to the original row so it will sort (move) with its original row but I'm unsure how to do it.
How can I approach it?
const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;
const comparer = (idx, asc) => (a, b) => ((v1, v2) =>
v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
)(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
document.querySelectorAll('.th-sortable').forEach(th => th.addEventListener('click', (() => {
const tbody = document.getElementsByClassName('js-sortable-table').item(0);
Array.from(tbody.querySelectorAll('tr:nth-child(n)'))
.sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
.forEach(tr => tbody.appendChild(tr));
})));
<table>
<thead>
<tr>
<th class="th-sortable" scope="col">Name</th>
<th class="th-sortable" scope="col">Surname</th>
<th class="th-sortable" scope="col">Age</th>
</tr>
</thead>
<tbody class="js-sortable-table">
<tr>
<td>
John
</td>
<td>
Carter
</td>
<td>
44
</td>
</tr>
<tr class="nested">
<th>
Article
</th>
<th>
Topic
</th>
<th>
Date
</th>
</tr>
<tr class="nested">
<td>
4
</td>
<td>
Music
</td>
<td>
12.06.2019
</td>
</tr>
<tr class="nested">
<td>
7
</td>
<td>
Free-time Activity
</td>
<td>
12.08.2019
</td>
</tr>
<tr class="nested">
<td>
8
</td>
<td>
Hobby
</td>
<td>
12.09.2019
</td>
</tr>
<tr>
<td>
Nicole
</td>
<td>
Odipie
</td>
<td>
21
</td>
</tr>
<tr class="nested">
<th>
Article
</th>
<th>
Topic
</th>
<th>
Date
</th>
</tr>
<tr class="nested">
<td>
11
</td>
<td>
Fashion
</td>
<td>
12.09.2019
</td>
</tr>
</tbody>
</table>
This isn't a complete solution but should work with some modification.
nest tables inside your main table for the articles
use this function from w3 to sort your tables
I would add the last name as a class to each nested table for a given person
sort the main table then embed the nested table for each person (sort the nested table if you need to before you embed)
UPDATE:
1) when you get the main table eliminate the nested tables
2) get each nested table
3) add the nested tables back in to the main table after it's been sorted
If you want more help you need to put something together and develop a step by step game plan. It will be easy to get specific help on a specific step. The more you break down the steps the easier and faster it will be to get help.
This really isn't that hard (maybe tedious) but just involves some basic JS operations.
function sortTable() {
var table, rows, switching, i, x, y, shouldSwitch;
table = document.getElementById("myTable");
switching = true;
/*Make a loop that will continue until
no switching has been done:*/
while (switching) {
//start by saying: no switching is done:
switching = false;
rows = table.rows;
/*Loop through all table rows (except the
first, which contains table headers):*/
for (i = 1; i < (rows.length - 1); i++) {
//start by saying there should be no switching:
shouldSwitch = false;
/*Get the two elements you want to compare,
one from current row and one from the next:*/
x = rows[i].getElementsByTagName("TD")[0];
y = rows[i + 1].getElementsByTagName("TD")[0];
//check if the two rows should switch place:
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
}
if (shouldSwitch) {
/*If a switch has been marked, make the switch
and mark that a switch has been done:*/
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
}
}
}
<table>
<thead>
<tr>
<th class="th-sortable" scope="col">Name</th>
<th class="th-sortable" scope="col">Surname</th>
<th class="th-sortable" scope="col">Age</th>
</tr>
</thead>
<tbody class="js-sortable-table">
<tr>
<td>
John
</td>
<td>
Carter
</td>
<td>
44
</td>
</tr>
<tr class="nested">
<th>
Article
</th>
<th>
Topic
</th>
<th>
Date
</th>
</tr>
<tr class="nested">
<td>
4
</td>
<td>
Music
</td>
<td>
12.06.2019
</td>
</tr>
<tr class="nested">
<td>
7
</td>
<td>
Free-time Activity
</td>
<td>
12.08.2019
</td>
</tr>
<tr class="nested">
<td>
8
</td>
<td>
Hobby
</td>
<td>
12.09.2019
</td>
</tr>
<tr>
<td>
Nicole
</td>
<td>
Odipie
</td>
<td>
21
</td>
</tr>
<tr class="nested">
<th>
Article
</th>
<th>
Topic
</th>
<th>
Date
</th>
</tr>
<tr class="nested">
<td>
11
</td>
<td>
Fashion
</td>
<td>
12.09.2019
</td>
</tr>
</tbody>
</table>

How add multiple rows plain html to existing table after a specific row dynamically

I have a table on a web page, I am trying to add multiple rows after first, second or third row dynamically.
<table class="sort-table">
<tr>
<th>State Owner</th>
<th>Number of Orders</th>
<th>Commission Total</th>
</tr>
<tr>
<td class="so_details" data-name="Adam Howard" data-soid="2"><a class="so_link">Adam Howard</a></td>
<td class="align-center">0</td>
<td class="currency align-right">0.00</td>
</tr>
<tr class="dashed-top">
<td class="total" colspan="2">Total</td>
<td class="currency align-right total">0.00</td>
</tr>
</table>
I have created some new tr elements dynamically. following is the html
<tr>
<td>ID1000</td>
<td class="op_details" data-name="Adam Howard" data-opid="ID1000"><a class="op_link">Adam Howard</a></td>
<td class="align-center">0</td>
<td class="currency align-right">0.00</td>
</tr>
<tr>
<td>ID06</td>
<td class="op_details" data-name="Cory McEwen" data-opid="ID06"><a class="op_link">Cory McEwen</a></td>
<td class="align-center">0</td>
<td class="currency align-right">0.00</td>
</tr>
<tr class="dashed-top">
<td class="total" colspan="3">Total</td>
<td class="currency align-right total">0.00</td>
</tr>
I want to insert the newly generated HTML tr elements after the first row or second or third etc.
I also want to adjust four td elements in newly created tr under the three td elements of a specific tr. as you can see in the code.
I have tried
let html = `<tr>
<td>ID1000</td>
<td class="op_details" data-name="Adam Howard" data-opid="ID1000"><a class="op_link">Adam Howard</a></td>
<td class="align-center">0</td>
<td class="currency align-right">0.00</td>
</tr>
<tr>
<td>ID06</td>
<td class="op_details" data-name="Cory McEwen" data-opid="ID06"><a class="op_link">Cory McEwen</a></td>
<td class="align-center">0</td>
<td class="currency align-right">0.00</td>
</tr>
<tr class="dashed-top">
<td class="total" colspan="3">Total</td>
<td class="currency align-right total">0.00</td>
</tr>`
(html).insertAfter($(this).closest('tr'));
//$('.sort-table > tbody > tr').eq(1).after(html);
But nothing happened to dom and it remains unchanged. Please help me in this regard.
JQuery insertAfter() or insertBefore() function can do your job.
insertAfter() // inserts after a selected element
insertBefore() // inserts before a selected element
syntax
$("Your html goes here").insertAfter($('yourtable selector tr:eq(row
index after which you want to insert the html)'));
Here is an example.
<table class="sort-table">
<tr> <td> 1 </td> </tr>
<tr> <td> 2 </td> </tr>
<tr> <td> 3 </td> </tr>
<tr> <td> 4 </td> </tr>
<tr> <td> 5 </td> </tr>
<tr> <td> 6 </td> </tr>
</table>
Now Javascript
var dynamicRow = `<tr>
<td>will insert after first row </td>
</tr>`;
$(dynamicRow).insertAfter($(".sort-table tr:eq(0)")); // 0th index is first-row
// The above 0th index using eq(0) can also be achieved using first-child pseudo selector
$(dynamicRow).insertAfter($(".sort-table tr:first-child"))
// if you want to insert after last row
dynamicRow = `<tr>
<td>will insert after last row </td>
</tr>`;
$(dynamicRow).insertAfter($(".sort-table tr:last-child"));
Note: to give the row index in tr:eq(rowindex), always remember that
it starts from 0 not 1. so
:eq(0) means first-row
:eq(1) means second-row
:eq(9) means (9+1) = 10th row

jquery - finding elements in a table and changing other elements based on findings

I'm trying to adapt other examples with similar questions here on stackoverflow... but am stumped right now.
Here's what my html table looks like after it's been rendered:
<table class="table table-striped" id="status">
<thead>
<tr>
<th>Name</th>
<th>REP</th>
<th>Package</th>
<th> CV</th>
<th>Latest CV</th>
<th>Custom </th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>asfasdf</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td class="package">tmm</td>
<td>tmm-4.2.7-r1</td>
<td>4.2.7-r1</td>
<td> </td>
<td class="status_button"><button type="button" class="btn btn-success"></button></td>
</tr>
<tr>
<td> </td>
<td> </td>
<td class="package">a-cis</td>
<td>a-cis-0.1.0-r0</td>
<td>0.1.0-r0</td>
<td> </td>
<td class="status_button"><button type="button" class="btn btn-danger"></button></td>
</tr>
</tbody>
</table>
What I need:
After the table has been rendered, I want to find all rows that have a danger button ("btn-danger") and change the color of the text in the "Package" cell / td to red.
Based on similar questions here on stackoverflow, here's what I have so far:
122 <script>
123 $( document ).ready(function() {
124 $('.status_button').each(function(i, n) {
125 console.log($(n.innerHTML));
126 //somehow id the sibling <td> that has class
127 //package and change the font color
128 //to red
129 });
130 });
131
132 </script>
The console.log matches a property in the object and displays... but my "if" statement fails.
I was trying to copy the contents of my console.log to paste in here but haven't been successful yet.
Any tips on how i can test the value of the button class and then alter the text color in the Package field would be appreciated
Thanks.
EDIT 1
So I changed the each function to look for the btn-danger class ... and that seems to work better because it filters more results.
But I guess I still need help changing the sibling td with the class "package" to display text in red.
122 <script>
123 $( document ).ready(function() {
124 $('.btn-danger').each(function(i, n) {
125 console.log($(n.innerHTML));
126 if ($(n.innerHTML) == "button.btn.btn-danger") {
127 alert('red!!');
128 };
129 });
130 });
131
132 </script>
You can use :has selector to filter all cells with class status_button having the button you are looking for.
In order to change the color of cell with class package you can use siblings.
The snippet:
$(function () {
$('.status_button:has("button.btn.btn-danger")').each(function(index, element) {
$(element).siblings('.package').css('color', 'red');
});
});
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<table class="table table-striped" id="status">
<thead>
<tr>
<th>Name</th>
<th>REP</th>
<th>Package</th>
<th> CV</th>
<th>Latest CV</th>
<th>Custom</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>asfasdf</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td class="package">tmm</td>
<td>tmm-4.2.7-r1</td>
<td>4.2.7-r1</td>
<td> </td>
<td class="status_button">
<button type="button" class="btn btn-success"></button>
</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td class="package">a-cis</td>
<td>a-cis-0.1.0-r0</td>
<td>0.1.0-r0</td>
<td> </td>
<td class="status_button">
<button type="button" class="btn btn-danger"></button>
</td>
</tr>
</tbody>
</table>
If you'd like to use jQuery, instead use the search for .btn-danger. It's simpler and does exactly what you want.
$(document).ready(function() {
$('.btn-danger').each(function(i, n) {
var thisRow = n.closest('tr');
$(thisRow).css("color", "red");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table table-striped" id="status">
<thead>
<tr>
<th>Name</th>
<th>REP</th>
<th>Package</th>
<th> CV</th>
<th>Latest CV</th>
<th>Custom </th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>asfasdf</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td class="package">tmm</td>
<td>tmm-4.2.7-r1</td>
<td>4.2.7-r1</td>
<td> </td>
<td class="status_button">
<button type="button" class="btn btn-success"></button>
</td>
</tr>
<tr>
<td> </td>
<td> </td>
<td class="package">a-cis</td>
<td>a-cis-0.1.0-r0</td>
<td>0.1.0-r0</td>
<td> </td>
<td class="status_button">
<button type="button" class="btn btn-danger"></button>
</td>
</tr>
</tbody>
</table>

How to Get text from table cell

This is what i have right now:
This is the table:
<table border='1'>
<tr>
<td>
Employee Code
</td>
<td>
FirstName
</td>
<td>
LastName
</td>
<td>
Address
</td>
</tr>
<tr class='display' onclick='hello();' >
<td id='trId1'>
E100
</td>
<td>
Alex
</td>
<td>
Stone
</td>
<td>
33 Wave Place
</td>
</tr>
<tr class='display' onclick='hello();' >
<td id='trId1'>
E200
</td>
<td>
Alex
</td>
<td>
Stone
</td>
<td>
33 Wave Place
</td>
</tr>
-----> etc...
</table>
This is the javascipt
<script>
function hello(){
var r = document.getElementById("trId1").innerHTML;
alert(r);
}
</script>
The JavaScript gets E100 when its the first row is clicked which is correct but when E200 row is clicked it still shows E100, how would i get E200 and so on when there is more data? Is there a javascript only solution
To start, you can't have two Id's on the page that are the same as that is invalid HTML5 and will cause errors in some browsers. The reason why you're getting what you're getting is because when looking for an ID, most browsers only look for one occurrence of an ID (because that is precisely what valid HTML is, 1 unique id per page). So to fix up your HTML code and you may also want to have a header for your table:
<table border='1'>
<thead>
<tr>
<th>
Employee Code
</th>
<th>
FirstName
</th>
<th>
LastName
</th>
<th>
Address
</th>
</tr>
</thead>
<tbody>
<tr class='display' onclick='hello(1);' >
<td class='trId1'>
E100
</td>
<td>
Alex
</td>
<td>
Stone
</td>
<td>
33 Wave Place
</td>
</tr>
<tr class='display' onclick='hello(2);' >
<td class='trId1'>
E200
</td>
<td>
Alex
</td>
<td>
Stone
</td>
<td>
33 Wave Place
</td>
</tr>
-----> etc...
</tbody>
</table>
Your best bet is to getElementsByClassName function and traverse the array to the one you want. (general change, code) Assuming you can't use JQuery at all for some reason:
<script>
function hello(rowClickedNumber){
var RowClicked = document.getElementsByClassName("trId1");
var r = RowClicked[0].innerHTML;
alert(r); //E100
var r = RowClicked[1].innerHTML;
alert(r); //E200
var r = RowClicked[rowClickedNumber].innerHTML;
alert(r);
}
</script>
However, an even simpler solution would be to use JQuery and would limit browser inconsistencies. After the document loads:
$(body).on("click", "tr", function(){
var getData =$(this).children(".trId1").getHTML();
console.log(getData);
});
Note: this is to allow when you inevitably add more items to the table (hence the reason why the code to get a child element of a row).
*EDIT: added the note
**EDIT: fixed the spelling and grammer
* EDIT: fixed the javascript function.
I have a solution for this. Please check the code and fiddle link below. Let me know if you have any question.
Fiddle
HTML:
<table border='1'>
<tr>
<td>
Employee Code
</td>
<td>
FirstName
</td>
<td>
LastName
</td>
<td>
Address
</td>
</tr>
<tr class='display' onclick='hello(this);' >
<td class='trId1'>
E100
</td>
<td>
Alex
</td>
<td>
Stone
</td>
<td>
33 Wave Place
</td>
</tr>
<tr class='display' onclick='hello(this);' >
<td class='trId1'>
E200
</td>
<td>
Alex
</td>
<td>
Stone
</td>
<td>
33 Wave Place
</td>
</tr>
</table>
JavaScript:
function hello(obj){
alert(obj.childNodes[1].innerText); //The first child being a text node.
}

Categories

Resources