I am trying to sort the table by total value. Link. This works but it fails when two table elements have same point.
I am trying to sort the table using javascript to order by total points at the end. The table is a dynamic one so W1, W2, W3 columns adds up to total. Each row is dynamically created as well.
Please help
const sortTotal = () => {
const tbl = [...document.getElementsByClassName("fl-table")][0];
const tbody = [...tbl.tBodies][0];
const oObjects = [];
[...tbody.rows].forEach(row => {
const cells = [...row.cells];
const obj = [...row.cells].map(cell => {
return cell.innerHTML;
});
oObjects.push(obj);
});
oObjects.sort((a, b) => a[a.length -2] > b[b.length -2] ? 1 : -1);
[...tbody.rows].forEach((row, i) => {
[...row.cells].forEach((cell, j) => {
cell.innerHTML = oObjects[i][j];
});
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onClick="sortTotal()">
Sort</button>
</button>
<table class="fl-table">
<thead>
<tr>
<th>Player</th>
<th>Player Name</th>
<th>W1</th>
<th>W2</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="agl-profile-img-new"><img src="https://via.placeholder.com/70C/O https://placeholder.com/"></td>
<td>Heather Rankin</td>
<td>4</td>
<td>21</td>
<td>25</td>
</tr>
<tr>
<td class="agl-profile-img-new"><img src="https://via.placeholder.com/70C/O https://placeholder.com/"></td>
<td>Stephen Puopolo</td>
<td>3</td>
<td>1</td>
<td>4</td>
</tr>
<tr>
<td class="agl-profile-img-new"><img src="https://via.placeholder.com/70C/O https://placeholder.com/"></td>
<td>Latheesh V M V</td>
<td>2</td>
<td>26</td>
<td>4</td>
</tr>
</tbody>
</table>
You are sorting by wrong column.
a[a.length -2] > b[b.length -2]
should be
a[a.length -1] > b[b.length -1]
and sort will make 25, 4, 4 by total
Related
I have the next HTML code:
<table border="1">
<tr>
<th>Nº</th>
<th>NOMBRE</th>
<th>AREA</th>
</tr>
<tbody id="curso">
<tr>
<td>1</td>
<td>Jose</td>
<td>Gramática</td>
</tr>
<tr>
<td>2</td>
<td>Luis</td>
<td>Gramática</td>
</tr>
<tr>
<td>3</td>
<td>Andrea</td>
<td>Gramática</td>
</tr>
<tr>
<td>4</td>
<td>Andrea</td>
<td>Idiomas</td>
</tr>
</tbody>
</table>
<p id="Cantidad"></p>
</body>
This code can count the number of rows using a criteria in the AREA field:
<script>
function ContarFila() {
var cantidadFilas = document.getElementById("curso").rows.length;
let resultados = {};
let elementos = document.querySelectorAll(
"table tbody tr > td:nth-child(3)"
);
elementos.forEach(elemento => {
if (resultados.hasOwnProperty(elemento.innerText)) {
resultados[elemento.innerText]++;
} else {
resultados[elemento.innerText] = 1;
}
});
console.log(resultados);
for (let indice in resultados) {
document.getElementById("Cantidad").innerHTML =
resultados['Gramática'];
};
}
window.onload=ContarFila();
</script>
When loading the page and using the 'Gramática' criteria of the 'AREA' field, the result is 3.
How do I include MULTIPLE CRITERIA with the 'NOMBRE' and 'AREA' field at the same time?
Example:
Using Criteria 1: 'Grammar'
Using Criteria 2: 'Luis'
RESULT: 1
THAK YOU!
If I understood you correctly, then perhaps this example below can help you:
function getResult(table, search = {}) {
const tableHeadCells = Array.from(table.tHead.rows[0].cells);
const tableBodyRows = Array.from(table.tBodies[0].rows);
const indexes = tableHeadCells.map((el) => el.dataset["label"]); // <= // ['index', 'nombre', 'area']
const count = tableBodyRows.reduce((acc, row) => {
isSearched = indexes.every(
(key, i) => !search[key] || search[key] === row.cells[i].innerText
);
return isSearched ? ++acc : acc;
}, 0);
return count;
}
const table = document.querySelector('table');
console.log('1 => ', getResult(table, {
area: 'Gramática'
}));
console.log('2 => ', getResult(table, {
nombre: 'Luis',
area: 'Gramática'
}));
console.log('3 => ', getResult(table, {
index: '3',
nombre: 'Andrea'
}));
<table border="1">
<thead>
<tr>
<th data-label="index">Nº</th>
<th data-label="nombre">NOMBRE</th>
<th data-label="area">AREA</th>
</tr>
</thead>
<tbody id="curso">
<tr>
<td>1</td>
<td>Jose</td>
<td>Gramática</td>
</tr>
<tr>
<td>2</td>
<td>Luis</td>
<td>Gramática</td>
</tr>
<tr>
<td>3</td>
<td>Andrea</td>
<td>Gramática</td>
</tr>
<tr>
<td>4</td>
<td>Andrea</td>
<td>Idiomas</td>
</tr>
</tbody>
</table>
Note that in the header of the table, the columns are indicated by data-attributes data-label in order to understand which column belongs to which keyword. And then, we just count the number of elements in the loop, which completely match the specified requirements for all columns
I need to sort these two tables in the same function. When I click name in first table so it will sort second table also by name.
I have this function where can sort table and it is working, but it only sorts one table.
What changes are needed to sort both tables?
function sortTable(table, column, asc = true) {
const dirModifier = asc ? 1 : -1;
const tBody = table.tBodies[0];
const rows = Array.from(tBody.querySelectorAll("tr"));
const sortedRows = rows.sort((a, b) => {
const aColText = a.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
const bColText = b.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
return aColText > bColText ? (1 * dirModifier) : (-1 * dirModifier);
});
while (tBody.firstChild) {
tBody.removeChild(tBody.firstChild);
}
tBody.append(...sortedRows);
table.querySelectorAll("th").forEach(th => th.classList.remove("th-sort-asc", "th-sort-desc"));
table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-asc", asc);
table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-desc", !asc);
}
document.querySelectorAll(".table-sortable th").forEach(headerCell => {
headerCell.addEventListener("click", () => {
const tableElement = headerCell.parentElement.parentElement.parentElement;
const headerIndex = Array.prototype.indexOf.call(headerCell.parentElement.children, headerCell);
const currentIsAscending = headerCell.classList.contains("th-sort-asc");
sortTable(tableElement, headerIndex, !currentIsAscending);
});
});
<table class="table-sortable">
<thead>
<tr>
<th>name</th>
<th>adress</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tom</td>
<td>Oslo</td>
<td>35</td>
</tr>
<tr>
<td>Per</td>
<td>London</td>
<td>29</td>
</tr>
<tr>
<td>Hary</td>
<td>Madrid</td>
<td>30</td>
</tr>
</tbody>
</table>
<table class="table-sortable">
<thead>
<tr>
<th>name</th>
<th>adress</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tom</td>
<td>Oslo</td>
<td>35</td>
</tr>
<tr>
<td>Per</td>
<td>London</td>
<td>29</td>
</tr>
<tr>
<td>Hary</td>
<td>Madrid</td>
<td>30</td>
</tr>
</tbody>
</table>
You can run sortTable function for each table.
var tables =document.getElementsByClassName("table-sortable");
sortTable(tables[0], headerIndex, !currentIsAscending);
sortTable(tables[1], headerIndex, !currentIsAscending);
function sortTable(table, column, asc = true) {
const dirModifier = asc ? 1 : -1;
const tBody = table.tBodies[0];
const rows = Array.from(tBody.querySelectorAll("tr"));
const sortedRows = rows.sort((a, b) => {
const aColText = a.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
const bColText = b.querySelector(`td:nth-child(${ column + 1 })`).textContent.trim();
return aColText > bColText ? (1 * dirModifier) : (-1 * dirModifier);
});
while (tBody.firstChild) {
tBody.removeChild(tBody.firstChild);
}
tBody.append(...sortedRows);
table.querySelectorAll("th").forEach(th => th.classList.remove("th-sort-asc", "th-sort-desc"));
table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-asc", asc);
table.querySelector(`th:nth-child(${ column + 1})`).classList.toggle("th-sort-desc", !asc);
}
document.querySelectorAll(".table-sortable th").forEach(headerCell => {
headerCell.addEventListener("click", () => {
const tableElement = headerCell.parentElement.parentElement.parentElement;
const headerIndex = Array.prototype.indexOf.call(headerCell.parentElement.children, headerCell);
const currentIsAscending = headerCell.classList.contains("th-sort-asc");
var tables =document.getElementsByClassName("table-sortable");
sortTable(tables[0], headerIndex, !currentIsAscending);
sortTable(tables[1], headerIndex, !currentIsAscending);
});
});
<table class="table-sortable">
<thead>
<tr>
<th>name</th>
<th>adress</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tom</td>
<td>Oslo</td>
<td>35</td>
</tr>
<tr>
<td>Per</td>
<td>London</td>
<td>29</td>
</tr>
<tr>
<td>Hary</td>
<td>Madrid</td>
<td>30</td>
</tr>
</tbody>
</table>
<table class="table-sortable">
<thead>
<tr>
<th>name</th>
<th>adress</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<tr>
<td>Tom</td>
<td>Oslo</td>
<td>35</td>
</tr>
<tr>
<td>Per</td>
<td>London</td>
<td>29</td>
</tr>
<tr>
<td>Hary</td>
<td>Madrid</td>
<td>30</td>
</tr>
</tbody>
</table>
I am trying to sort the table using javascript to order by total points at the end. The table is a dynamic one so W1, W2, W3 columns adds up to total. Is there way to order rows them by total in javascript. Each row is dynamically created as well.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="fl-table">
<thead>
<tr>
<th>Player</th>
<th>Player Name</th>
<!-- <th>W1</th>
<th>W2</th> -->
<th>W1</th>
<th>W2</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td class="agl-profile-img-new"><img src="https://via.placeholder.com/70
C/O https://placeholder.com/"></td>
<td>Heather Rankin</td>
<td>4</td>
<td>21</td>
<td>25</td>
</tr>
<tr>
<td class="agl-profile-img-new"><img src="https://via.placeholder.com/70
C/O https://placeholder.com/"></td>
<td>Stephen Puopolo</td>
<td>3</td>
<td>1</td>
<td>4</td>
</tr>
<tr>
<td class="agl-profile-img-new"><img src="https://via.placeholder.com/70
C/O https://placeholder.com/"></td>
<td>Latheesh V M V</td>
<td>2</td>
<td>26</td>
<td>28</td>
</tr>
</tbody>
<tbody>
</tbody>
</table>
Is there is any way? Please help
can you gather the cells into object and sort them like this. https://jsfiddle.net/e4oscnz8/4/
const sortTotal = () => {
const tbl = [...document.getElementsByClassName("fl-table")][0];
const tbody = [...tbl.tBodies][0];
const oObjects = [];
[...tbody.rows].forEach(row => {
const cells = [...row.cells];
const obj = [...row.cells].map(cell => {
return cell.innerHTML;
});
oObjects.push(obj);
});
oObjects.sort((a, b) => a[a.length -2] > b[b.length -2] ? 1 : -1);
[...tbody.rows].forEach((row, i) => {
[...row.cells].forEach((cell, j) => {
cell.innerHTML = oObjects[i][j];
});
});
}
push tr rows into array or object and sort by your custom sort function: https://jsfiddle.net/2dq7m8k9/
you are using jquery so life is good :)
function SortByTotal(tr1, tr2){//descending sorting
var total1 = parseInt(tr1.find('td:last-child').text());
var total2 = parseInt(tr2.find('td:last-child').text());
return ((total1 > total2) ? -1 : ((total1 < total2) ? 1 : 0));
}
var trs=new Array();
$('#mytable tbody').first().children('tr').each(function(){
trs.push($(this).clone());
});
trs.sort(SortByTotal);
$('#mytable tbody').first().empty();
var i=0;
for (i = 0; i < trs.length; i++) {
$('#mytable tbody').first().append(trs[i]);
}
I have a following html table and jQuery function to sort the table by table header columns:
//sort summary table
$('th').click(function() {
var table = $(this).parents('table').eq(0)
var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
this.asc = !this.asc;
if (!this.asc) {
rows = rows.reverse();
}
for (var i = 0; i < rows.length; i++) {
table.append(rows[i]);
}
});
function comparer(index) {
return function(a, b) {
var valA = getCellValue(a, index),
valB = getCellValue(b, index)
return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.localeCompare(valB)
}
}
function getCellValue(row, index) {
return $(row).children('td').eq(index).text();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>S.No.</th>
<th>School</th>
<th>Campus City / State</th>
<th>Campaign Name</th>
<th>Work Order</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>EL PASO UNIVERSITY</td>
<td> EL PASO/TX</td>
<td>Full Campaign</td>
<td>#10055</td>
</tr>
<tr>
<td>2</td>
<td>DALLAS UNIVERSITY</td>
<td> DALLAS/TX</td>
<td>Mini Campaign</td>
<td>#10056</td>
</tr>
<tr>
<td>3</td>
<td>MINNESOTA UNIVERSITY</td>
<td> MINNEAPOLIS/MN</td>
<td>Full Campaign</td>
<td>#10059</td>
</tr>
</tbody>
</table>
All the functionality for sorting table is working fine. But couldn't figure out how to let user know current ordering of
table is sorted by which column. I just want to add simple css color to separate the currently clicked column. Any idea?
Adding the css colors to all headers except the clicked one will do the trick. This can be achieved by something like:
$('th').css({'background-color' : '#808080'});
$('th').css({'color' : '#FFFFFF'});
$(this).css('background-color', '#6f3d3d'); //change the background color
$(this).css({'color' : '#0000FF'}); //change the font color
Just add the above code to your function:
//sort summary table
$('th').click(function(){
//add your css trick
$('th').css({'background-color' : '#808080'});
$('th').css({'color' : '#FFFFFF'});
$(this).css('background-color', '#6f3d3d');
$(this).css({'color' : '#0000FF'});
var table = $(this).parents('table').eq(0)
var rows = table.find('tr:gt(0)').toArray().sort(comparer($(this).index()))
this.asc = !this.asc
if (!this.asc) {
rows = rows.reverse();
}
for (var i = 0; i < rows.length; i++) {
table.append(rows[i]);
}
});
function comparer(index) {
return function(a, b) {
var valA = getCellValue(a, index),
valB = getCellValue(b, index)
return $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.localeCompare(valB)
}
}
function getCellValue(row, index) {
return $(row).children('td').eq(index).text();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>S.No.</th>
<th>School</th>
<th>Campus City / State</th>
<th>Campaign Name</th>
<th>Work Order</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>EL PASO UNIVERSITY</td>
<td> EL PASO/TX</td>
<td>Full Campaign</td>
<td>#10055</td>
</tr>
<tr>
<td>2</td>
<td>DALLAS UNIVERSITY</td>
<td> DALLAS/TX</td>
<td>Mini Campaign</td>
<td>#10056</td>
</tr>
<tr>
<td>3</td>
<td>MINNESOTA UNIVERSITY</td>
<td> MINNEAPOLIS/MN</td>
<td>Full Campaign</td>
<td>#10059</td>
</tr>
</tbody>
</table>
You just need to add a condition to your JS that will check if this column is currently the sorted-by column,
$('th').click(function() {
if (!$(this).hasClass('sort-by')) {
$('th').removeClass('sort-by');
$(this).addClass('sort-by');
// logic for sorting by this column
}
});
and add a simple rule to your CSS
.sort-by {
background-color: blue; // or whatever
}
This code works but checks only the first column. I want to check the 2nd column instead with the points. How do I alter it?
HTML Table:
<table width="100%">
<thead>
<tr>
<th width="60%">Name</th>
<th width="20%">School</th>
<th width="20%">Points</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="4"><h1>Event 1</h1></td>
<td>School1</td>
<td>74</td>
</tr>
<tr>
<td>School2</td>
<td>69</td>
</tr>
<tr>
<td>School3</td>
<td>71</td>
</tr>
<tr>
<td>School4</td>
<td>11</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="4"><h1>Event 2</h1></td>
<td>School1</td>
<td>34</td>
</tr>
<tr>
<td>School5</td>
<td>29</td>
</tr>
<tr>
<td>School3</td>
<td>62</td>
</tr>
<tr>
<td>School7</td>
<td>15</td>
</tr>
</tbody>
</table>
jQuery:
var $tbody = $('#caltbl tbody');
$tbody.find('tr').sort(function (a, b) {
var tda = $(a).find('td:eq(0)').text();
var tdb = $(b).find('td:eq(0)').text();
// if a < b return 1
return tda > tdb ? 1
// else if a > b return -1
: tda < tdb ? -1
// else they are equal - return 0
: 0;
}).appendTo($tbody);
How do I got about this?
JSFIDDLE
EDIT: I'm sorry guys but my live code is different with rowspan being used. Is there a possibility to have this in ascending order so that the events are sorted differently?
eq(0) means you are using the first index. Change it to eq(1) so that it can consider the second index.
var tda = $(a).find('td:eq(1)').text();
var tdb = $(b).find('td:eq(1)').text();
You can sort the trs. Detach the td and insert to an array. Then append them back to each row
Add some class to simplify coding.
JSFIDDLE
HTML
<table width="100%">
<thead>
<tr>
<th width="60%">Name</th>
<th width="20%">School</th>
<th width="20%">Points</th>
</tr>
</thead>
<tbody>
<tr class="event1">
<td rowspan="4"><h1>Event 1</h1></td>
<td>School1</td>
<td class="point">74</td>
</tr>
<tr class="event1">
<td>School2</td>
<td class="point">69</td>
</tr>
<tr class="event1">
<td>School3</td>
<td class="point">71</td>
</tr>
<tr class="event1">
<td>School4</td>
<td class="point">11</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
<tr>
<td rowspan="4"><h1>Event 2</h1></td>
<td>School1</td>
<td>34</td>
</tr>
<tr>
<td>School5</td>
<td>29</td>
</tr>
<tr>
<td>School3</td>
<td>62</td>
</tr>
<tr>
<td>School7</td>
<td>15</td>
</tr>
</tbody>
</table>
JavaScript
var $tbody = $(' tbody');
var array = [];
$tbody.find('.event1').sort(function (a, b) {
var tda = $(a).find('.point').text();
var tdb = $(b).find('.point').text();
return tda - tdb;
}).each(function (idx, tr) {
array.push($(tr).children('td').not('[rowspan]').detach());
});
$.each(array, function (idx, obj) {
$(obj).appendTo($('.event1:eq(' + idx + ')'));
});
The JavaScript only applies to event1. You can simply modify it for arbitrary events.
Change the index as Mayank Pandey said. And..
Since your second column is number, you can just return their difference.
var $tbody = $('#caltbl tbody');
$tbody.find('tr').sort(function (a, b) {
var tda = parseInt($(a).find('td:eq(1)').text(), 10); // always use the base number
var tdb = parseInt($(b).find('td:eq(1)').text(), 10);
return tda - tdb;
}).appendTo($tbody);