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>
Related
I am working on Django framework and stuck in a bad situation. I have my Data table that is fetched from database and displaying in a table form. At the end of the table there are multiple checkboxes which is used to customize the data and display the only data for which I have clicked on single or multiple checkboxes. After clicking on checkbox / checkboxes data have to display in table form.
<head>
<script>
function getvalues()
{
let selected = new Array();
var chckbox = document.getElementById("tab1");
var selchk = chckbox.getElementsByTagName("input");
for(var i=0; i<selchk.length;i++)
{
if(selchk[i].checked)
{
selected.push(selchk[i].value);
}
}
if(selected.length> 0)
{
document.getElementById("displayvalues").innerHTML= selected;
}
};
</script>
</head>
<body>
<table border = "1">
<tr>
<th> ID </th>
<th> NAME </th>
<th> EMAIL </th>
<th> SALARY </th>
<th> PHONE </th>
</tr>
{%for getdata in EmployeeDetails %}
<tr>
<td> {{getdata.id}}</td>
<td> {{getdata.empname}}</td>
<td> {{getdata.email}}</td>
<td> {{getdata.salary}}</td>
<td> {{getdata.phone}}</td>
</tr>
{% endfor %}
</table>
<table id = "tab1">
<tr>
<td> {%for display in EmployeeDetails %}
<input type="checkbox" value="{{display.salary}}" /> {{display.salary}}
{% endfor %}
</td>
</tr>
</table>
<input id="but1" type="button" value="display records" onclick="getvalues()"/>
<b id="displayvalues"></b>
</body>
As you can see in image when I click on any checkbox It just gives me checkbox value not the entire row. I want entire row result by clicking on single or multiple checkboxes and it should display in form of table pertaining rows.
Kindly Help me to get out of this.
Your javascript function needs to find more than the checkbox value.
You also need the rows with the corresponding salary.
To achieve this, I would add a class corresponding to the salary on every row. Then I would use JavaScript's QuerySelectorAll to get every row with the class corresponding to the salary, hide every row and show the matching rows.
I added a "a" before every class because they can't start with a number.
function getvalues()
{
let checkboxes = document.getElementById("tab1");
let table = document.getElementById("table");
var selchk = document.getElementsByTagName("input");
let selected = [];
for(var i=0; i<selchk.length;i++)
{
if(selchk[i].checked)
{
selected.push(selchk[i].value);
}
}
var query = "#tr";
for(var j = 0; j < selected.length; j++) {
query = query + ", .a" + selected[j];
}
if (query !== "")
var rows = table.querySelectorAll(query); // Every element having a class corresponding to the salary you want
else var rows = [];
table.querySelectorAll("tr").forEach((r) => r.style.display = "none");
rows.forEach((r) => { // For every row r
r.style.display = ""; // Hide r
});
};
<table border = "1">
<tr>
<th> ID </th>
<th> NAME </th>
<th> EMAIL </th>
<th> SALARY </th>
<th> PHONE </th>
</tr>
<tr class="a12">
<td> 1</td>
<td> test</td>
<td> tset#test</td>
<td> 12</td>
<td> 0606060606</td>
</tr>
<tr class="a22">
<td> 2</td>
<td> test2</td>
<td> tse2t#test</td>
<td> 22</td>
<td> 0606060626</td>
</tr>
</table>
<table id = "tab1">
<tr>
<td>
<input type="checkbox" value="12" /> 12 </td>
<td>
<input type="checkbox" value="22" /> 22 </td>
</tr>
</table>
<table border = "1">
<tr>
<th> ID </th>
<th> NAME </th>
<th> EMAIL </th>
<th> SALARY </th>
<th> PHONE </th>
</tr>
<tbody id="table">
<tr class="a12">
<td> 1</td>
<td> test</td>
<td> tset#test</td>
<td> 12</td>
<td> 0606060606</td>
</tr>
<tr class="a22">
<td> 2</td>
<td> test2</td>
<td> tse2t#test</td>
<td> 22</td>
<td> 0606060626</td>
</tr>
</tbody>
</table>
<input id="but1" type="button" value="display records" onclick="getvalues()"/>
<b id="displayvalues"></b>
ISOLATED TEMPLATE FOR CLARITY :
<table border = "1">
<tr>
<th> ID </th>
<th> NAME </th>
<th> EMAIL </th>
<th> SALARY </th>
<th> PHONE </th>
</tr>
{%for getdata in EmployeeDetails %}
<tr class="a{{ getdata.salary }}">
<td> {{getdata.id}}</td>
<td> {{getdata.empname}}</td>
<td> {{getdata.email}}</td>
<td> {{getdata.salary}}</td>
<td> {{getdata.phone}}</td>
</tr>
{% endfor %}
</table>
<table id = "tab1">
<tr>
<td> {%for display in EmployeeDetails %}
<input type="checkbox" value="{{display.salary}}" /> {{display.salary}}
{% endfor %}
</td>
</tr>
</table>
<input id="but1" type="button" value="display records" onclick="getvalues()"/>
<b id="displayvalues"></b>
<table border = "1">
<tr>
<th> ID </th>
<th> NAME </th>
<th> EMAIL </th>
<th> SALARY </th>
<th> PHONE </th>
</tr>
<tbody id="table">
{%for getdata in EmployeeDetails %}
<tr class="a{{ getdata.salary }}">
<td> {{getdata.id}}</td>
<td> {{getdata.empname}}</td>
<td> {{getdata.email}}</td>
<td> {{getdata.salary}}</td>
<td> {{getdata.phone}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
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
}
}
This question already has answers here:
Change table columns order
(4 answers)
Closed 1 year ago.
Firstly, My English is so bad. SORRY ABOUT THAT!
I have a table like this:
<table>
<tr>
<th> heading 1 </th>
<th> heading 2 </th>
</tr>
<tr>
<td> data 2 </td>
<td> data 2 </td>
</tr>
But sometime i want it like this (order of td & th tags has changed):
<table>
<tr>
<th> heading 2 </th>
<th> heading 1 </th>
</tr>
<tr>
<td> data 2 </td>
<td> data 1 </td>
</tr>
How I can accomplish this?
Thank you!
You can easily do it with css direction tag. And then change the table class using javaScript DOM.
var table = document.getElementById('table');
function changeDirection() {
table.className = "table-ltr";
}
.table-rtl {
direction: rtl;
}
.table-ltr {
direction: ltr;
}
<button onClick="changeDirection()">Switch</button>
<table class="table-rtl" id="table">
<tr>
<th> heading 1 </th>
<th> heading 2 </th>
</tr>
<tr>
<td> data 2 </td>
<td> data 2 </td>
</tr>
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>
i'm struggling trying to perform the following operation:
I've this table:
<table id="saleDetails" class="table table-hover table-condensed">
<thead>
<tr>
<th>Code </th>
<th>Description </th>
<th>Price </th>
<th>Quantity </th>
</tr>
</thead>
<tbody>
<tr>
<th> 001 </th>
<th> One description </th>
<th> 30.5 </th>
<th> <input type="number"></input> </th>
</tr>
<tr>
<th> 002 </th>
<th> Some description </th>
<th> 120 </th>
<th> <input type="number"></input> </th>
</tr>
<tr>
<th> 003 </th>
<th> Other description </th>
<th> 300.5 </th>
<th> <input type="number"></input> </th>
</tr>
</tbody>
</table>
what i'm trying to do is get the unitPrice and multiply it by the quantity input value to get the subtotal for each line.
i got the unitPrice with this sentence for each cell in column 3:
$('#saleDetails tr td:nth-child(3)').each(function () {
console.log( $(this).text() );
});
but i would like to perform the operation unitPrice * quantity (quantity is a input component) and i'm not sure how get the unitPrice and quantity at the same time (I'm not sure if that's possible) for each iteration on the table.
Any help will be welcome.
Thanks.
You can do something like this:
$('#saleDetails tr').each(function () {
var price = $(this).find("td:nth-child(3)").text()
var quantity = $(this).find("td:nth-child(4) input").val()
console.log( quantity + " " + price);
});
You can use DOM traversal method to target the input. Use .closest() to traverse up to TR element the use .find() to target the input
$('#saleDetails tr td:nth-child(3)').each(function () {
var quantity = $(this).closest('tr').find('input').val();
console.log( $(this).text(), quantity );
});
$('#saleDetails tr td:nth-child(3)').each(function() {
var quantity = $(this).closest('tr').find('input').val();
console.log($(this).text().trim(), quantity);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="saleDetails" class="table table-hover table-condensed">
<thead>
<tr>
<th>Code </th>
<th>Description </th>
<th>Price </th>
<th>Quantity </th>
</tr>
</thead>
<tbody>
<tr>
<td> 001 </td>
<td> One description </td>
<td> 30.5 </td>
<td> <input type="number" value="5" /></d>
</tr>
</tbody>
</table>
There are various method, you can also use
var quantity = $(this).closest('td').next().find('input').val();
Try this code by using class selector; jsfiddle
html:
<table id="saleDetails" class="table table-hover table-condensed">
<thead>
<tr>
<th>Code </th>
<th>Description </th>
<th>Price </th>
<th>Quantity </th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td> 001 </td>
<td> One description </td>
<td class="unitprice"> 30.5 </td>
<td> <input type="number" class="quantity" /> </td>
<td class="total"></td>
</tr>
<tr>
<td> 002 </td>
<td> Some description </td>
<td class="unitprice"> 120 </td>
<td> <input type="number" class="quantity" /> </td>
<td class="total"></td>
</tr>
</tbody>
</table>
and js:
$('#saleDetails tr').on("change", ".quantity", function (event) {
var $row = $(event.delegateTarget);
var price = $row.find(".unitprice").text();
var quantity = $row.find(".quantity").val();
var total = price*quantity;
$row.find(".total").text(total);
});