Sort table by sub-string - javascript

I'm trying to sort a table by course number, but I need to use a substring to sort by number. The course name looks like CX-001 for example, I wanting to ignore the first three characters. I'm using Vanilla Javascript. I'm not sure where to apply the substring, but I know I got it wrong.
function sortSubNum(subNum) {
var switchcount = 0;
var table = document.getElementById("myTable2").substring(2);
var switching = true;
// Set the sorting direction to ascending:
var dir = "asc";
/* Make a loop that will continue until
no switching has been done: */
while (switching) {
switching = false;
var rows = table.rows;
var shouldSwitch;
for (var i = 1; i < (rows.length - 1); i++) {
var x = rows[i].getElementsByTagName("TD")[subNum];
var y = rows[i + 1].getElementsByTagName("TD")[subNum];
//var resX = x.substring(2);
//var resY = y.substring(2);
if (dir === "asc") {
if (Number(x.textContent.substring(2)) < Number(y.textContent.substring(2))) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
} else if (dir === "desc") {
if (Number(x.textContent.substring(2)) > Number(y.textContent.substring(2))) {
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
switchcount++;
} else {
if (switchcount === 0 && dir === "asc") {
dir = "desc";
switching = true;
}
}
}
}
sortSubNum(1);
<table id="myTable2">
<thead>
<tr>
<th>Teacher</th>
<th>Course Number</th>
</tr>
</thead>
<tbody>
<tr>
<td>Smith</td>
<td>CS-301</td>
</tr>
<tr>
<td>Kelly</td>
<td>CX-201</td>
</tr>
<tr>
<td>Park</td>
<td>CS-001</td>
</tr>
</tbody>
</table>

Although you already found problem in your code but my solution is based on #Patrick Roberts suggestion given in comment.
Instead of implementing your own sorting method directly on the DOM, consider initializing an Array of elements and calling Array.prototype.sort(), then reinserting the newly ordered elements back into the table. It would be a lot faster and less error-prone
function sortTable(tbody, col, asc){
var rows = tbody.rows;
var rowsLen = tbody.rows.length;
var arr = new Array();
var i, j, cells, cellLen;
// fill the array with values from the table
for(i = 0; i < rowsLen; i++){
cells = rows[i].cells;
cellLen = cells.length;
arr[i] = new Array();
for(j = 0; j < cellLen; j++){
arr[i][j] = cells[j].innerHTML;
}
}
//short the array
arr.sort(function(a, b){
//this is your use case.sort the data in array after spilt.
var aCol=a[col].split("-")[1];
var bCol=b[col].split("-")[1];
return (aCol == bCol) ? 0 : ((aCol > bCol) ? asc : -1*asc);
});
for(i = 0; i < rowsLen; i++){
arr[i] = "<td>"+arr[i].join("</td><td>")+"</td>";
}
tbody.innerHTML = "<tr>"+arr.join("</tr><tr>")+"</tr>";
}
var tbody=document.getElementById("myTable2Tbody");
sortTable(tbody,1, 1);
//for asc use 1,for dsc use -1
<table id ="myTable2">
<thead>
<tr>
<th>Teacher</th>
<th>Course Number</th>
</tr>
</thead>
<tbody id ="myTable2Tbody">
<tr>
<td>Smith</td>
<td>CS-301</td>
</tr>
<tr>
<td>Kelly</td>
<td>CX-201</td>
</tr>
<tr>
<td>Park</td>
<td>CS-001</td>
</tr>
</tbody>
</table>

Check out this solution using Array.sort
var tbody = document.querySelector('#myTable2 tbody')
var trs = tbody.querySelectorAll('tr')
var sorted = [...trs].sort((tra, trb) => {
var courseA = tra.querySelectorAll('td')[1].innerText
var courseB = trb.querySelectorAll('td')[1].innerText
return courseA.split('-')[1] - courseB.split('-')[1]
})
tbody.innerHTML = '';
sorted.forEach(tr => tbody.appendChild(tr))
<table id="myTable2">
<thead>
<tr>
<th>Teacher</th>
<th>Course Number</th>
</tr>
</thead>
<tbody>
<tr>
<td>Smith</td>
<td>CS-301</td>
</tr>
<tr>
<td>Kelly</td>
<td>CX-201</td>
</tr>
<tr>
<td>Park</td>
<td>CS-001</td>
</tr>
</tbody>
</table>

Removed substring from var table. Also, I changed conditionals in the for loop from
if (Number(x.textContent.substring(2)) < Number(y.textContent.substring(2)))
to
if(x.textContent.substring(2) < y.textContent.substring(2))
function sortSubNum(subNum) {
var switchcount = 0;
var table = document.getElementById("myTable2");
var switching = true;
// Set the sorting direction to ascending:
var dir = "asc";
/* Make a loop that will continue until
no switching has been done: */
while(switching){
switching = false;
var rows = table.rows;
var shouldSwitch;
for(var i = 1; i < (rows.length - 1); i ++){
var x = rows[i].getElementsByTagName("TD")[subNum];
var y = rows[i + 1].getElementsByTagName("TD")[subNum];
//var resX = x.substring(2);
//var resY = y.substring(2);
if(dir === "asc"){
if(x.textContent.substring(2) < y.textContent.substring(2)) {
//if so, mark as a switch and break the loop:
shouldSwitch = true;
break;
}
}else if(dir === "desc"){
if(x.textContent.substring(2) > y.textContent.substring(2)){
shouldSwitch = true;
break;
}
}
}
if(shouldSwitch){
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
switchcount++;
}else{
if (switchcount === 0 && dir === "asc") {
dir = "desc";
switching = true;
}
}
}
}

Related

Sort html tables with Javascript

I have a javascript code that works well when sorting html tables like this:
<table id="tableBeingDecomm" align="center" render-area="beingDecom">
<thead>
<tr>
<th id="beingDecom"><a href="#">
Server Name
<img src='/icons/sort.png' width='20' height='20' style='display:inline;'>
</a></th>
<th id="beingDecomDate"><a href="#">
Deleting Date
<img src='/icons/sort.png' width='20' height='20' style='display:inline;'>
</a></th>
</tr>
</thead>
<tbody render-action="loop">
<tr render-data="jsonBeingDecom">
<td>{!serverName!}</td>
<td>{!deletingDate!}</td>
</tr>
</tbody>
</table>
but not with this new table below, no errors and the page becomes unresponsive:
<table id="PortsTable" align="center" render-area="dcPorts">
<thead>
<tr>
<th id="ServerNameHeader1"><a href="#">
Server Name
<img src='/icons/sort.png' width='20' height='20' style='display:inline;'>
</a></th>
<th id="ServerNameHeader2"><a href="#">
Destination
<img src='/icons/sort.png' width='20' height='20' style='display:inline;'>
</a></th>
<th>Port 53</th>
<th>Port 88</th>
<th>Port 135</th>
<th>Port 139</th>
<th>Port 389</th>
<th>Port 445</th>
<th>Port 464</th>
<th>Port 636</th>
</tr>
</thead>
<tbody render-action="loop">
<tr render-data="jsonPorts">
<td>{!Server Name!}</td>
<td>{!Destination!}</td>
<td>{!Port 53!}</td>
<td>{!Port 88!}</td>
<td>{!Port 135!}</td>
<td>{!Port 139!}</td>
<td>{!Port 389!}</td>
<td>{!Port 445!}</td>
<td>{!Port 464!}</td>
<td>{!Port 636!}</td>
</tr>
</tbody>
</table>
and here is my code:
function sortTable(tableId, column) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById(tableId);
switching = true;
dir = "asc";
while (switching) {
switching = false;
rows = table.rows;
for (i = 1; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("td")[column];
y = rows[i + 1].getElementsByTagName("td")[column];
if (!isNaN(x.innerHTML) && !isNaN(y.innerHTML)) {
if (dir == "asc") {
if (Number(x.innerHTML) > Number(y.innerHTML)) {
shouldSwitch= true;
break;
}
} else if (dir == "desc") {
if (Number(x.innerHTML) < Number(y.innerHTML)) {
shouldSwitch= true;
break;
}
}
} else {
if (dir == "asc") {
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
shouldSwitch= true;
break;
}
} else if (dir == "desc") {
if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
shouldSwitch= true;
break;
}
}
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
switchcount ++;
} else {
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
let sortOrder = "asc";
The way I invoke the function is this:
document.getElementById("ServerNameHeader1").addEventListener("click", function() {
sortTable("PortsTable", 0);
});
document.getElementById("ServerNameHeader2").addEventListener("click", function() {
sortTable("PortsTable", 1);
});
I guess the function is running repeatedly, but I don't know why. The html structure is the same as the other tables
Following #Gary's advice I rewrote the function and now it works. I did some search and found out that the createDocumentFragment() method turns useful when dealing with large dataset as it is my case, so I've used it.
function sortTable(tableId, column) {
const table = document.getElementById(tableId);
const tbody = table.getElementsByTagName("tbody")[0];
const rows = Array.from(tbody.getElementsByTagName("tr"));
// Extract the data into a two-dimensional array
const rowData = rows.map((row) => {
const cells = Array.from(row.getElementsByTagName("td"));
return cells.map((cell) => cell.innerText);
});
rowData.sort((a, b) => {
const aValue = a[column];
const bValue = b[column];
if (aValue < bValue) {
return -1;
} else if (aValue > bValue) {
return 1;
} else {
return 0;
}
});
// Create a new document fragment with the sorted rows
const fragment = document.createDocumentFragment();
for (let i = 0; i < rowData.length; i++) {
const cells = rowData[i];
const row = document.createElement("tr");
for (let j = 0; j < cells.length; j++) {
const cell = document.createElement("td");
cell.innerText = cells[j];
row.appendChild(cell);
}
fragment.appendChild(row);
}
tbody.innerHTML = "";
tbody.appendChild(fragment);
}

Sort Table incorporated in GAS

Hi I would like to ask if why the sort table function is not working if I put a condition wherein only specific data will be shown in the table. However, if I show all the data from the spreadsheet to the table the sorting function works fine. See sample code below:
<table id="vllist" class="vllist1">
<? var data = SpreadsheetApp
.openById('spreadsheet ID')
.getSheetByName("VL Request")
.getDataRange()
.getValues();
var timeStamp = [0];
var rid = [1];
var ldap = [2];
var aname = [7];
var tlname = [8];
var lob = [9];
var dovl = [5];
var userName = Session.getEffectiveUser().getUsername();
?>
<tr>
<th colspan=5>Scheduler VIEW</th>
</tr>
<tr>
<th onclick="sortTable(0)">Request ID</th>
<th onclick="sortTable(1)">LDAP</th>
<th onclick="sortTable(2)">Agent Name</th>
<th onclick="sortTable(3)">Team Lead</th>
<th onclick="sortTable(4)">Lane</th>
<th onclick="sortTable(5)">Date of VL</th>
</tr>
<? for (var i = 1; i < data.length; i++) { ?>
<tr>
<?var today = new Date();
if (data[i][dovl] > today) { ?>
<?
var schedtimeStamp = data[i][schedtimeStampappr];
var POCtimeStamp = data[i][POCtimeStampappr];
var vldate = data[i][dovl];
var formattedDateVL = (vldate.getMonth()+1) + '/' + vldate.getDate() + '/' + vldate.getYear();
?>
<td>
<?= data[i][rid] ?>
</td>
<td>
<?= data[i][ldap] ?>
</td>
<td>
<?= data[i][aname] ?>
</td>
<td>
<?= data[i][tlname] ?>
</td>
<td>
<?= data[i][lob] ?>
</td>
<td>
<?= [formattedDateVL] ?>
</td>
<? } ?>
</tr>
<? } ?>
</table>
<script>
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("vllist");
switching = true;
//Set the sorting direction to ascending:
dir = "asc";
/*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 = 2; 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")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
/*check if the two rows should switch place,
based on the direction, asc or desc:*/
if (dir == "asc") {
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
//if so, mark as a switch and break the loop:
shouldSwitch= true;
break;
}
} else if (dir == "desc") {
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;
//Each time a switch is done, increase this count by 1:
switchcount ++;
} else {
/*If no switching has been done AND the direction is "asc",
set the direction to "desc" and run the while loop again.*/
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
</script>
Please check the code and let me know if there any other way or alternative to make a sorting table even if not all the data from the spreadsheet will be shown on the table. I just only the sorting to be fixed when each header will be clicked. :)
Well first of all write this as a function on the server.
var data = SpreadsheetApp
.openById('spreadsheet ID')
.getSheetByName("VL Request")
.getDataRange()
.getValues();
var timeStamp = [0];
var rid = [1];
var ldap = [2];
var aname = [7];
var tlname = [8];
var lob = [9];
var dovl = [5];
var userName = Session.getEffectiveUser().getUsername();
When you get that done we can move on to the next step.

Sorting Table data onclick <th>in Google-App script

I am trying to sort the data(asc or desc) in the table. For this one I want to sort the Date of VL & Date/Time of Application whenever I click on each header. However, my current code is not doing anything everytime I click it. But when I tried it on a static data it's working.
Here's my code below:
<? var data = SpreadsheetApp
.openById('sheet ID')
.getSheetByName("VL Request")
.getDataRange()
.getValues();
var timeStamp = [0];
var rid = [1];
var ldap = [2];
var aname = [7];
var lob = [9];
var dovl = [5];
var rol = [6];
var tlapprov = [12];
var tlrem = [14];
var stat = [13];
var schedrem = [11];
var tl = [3];
var pocldap = [15];
var omldap = [16];
var userName = Session.getEffectiveUser().getUsername();
?>
<table id="vllist" class="vllist2">
<tr>
<th colspan=11>POC VIEW</th>
</tr>
<tr>
<th colspan=11>Application for Date Range: <?= [formattedStart] ?> - <?= [formattedEnd] ?></th>
</tr>
<tr>
<th style="display:none;">Request ID</th>
<th>LDAP</th>
<th>Agent Name</th>
<th>Lane</th>
<th onclick="sortTable(4)">Date of VL</th>
<th>Reason of Leave</th>
<th>POC Approval</th>
<th>POC Remarks</th>
<th>Scheduler's Approval</th>
<th>Scheduler's Remarks</th>
<th onclick="sortTable(10)">Date/Time of Application</th>
</tr>
<? for (var i = 1; i < data.length; i++) { ?>
<tr>
<? if ((data[i][tlapprov] === "Pending") && ((data[i][pocldap] === userName) || (data[i][omldap] === userName)) && (data[i][dovl] >= startDate) && (data[i][dovl] <= endDate)) { ?>
<?
var vldate = data[i][dovl];
var formattedDateVL = (vldate.getMonth()+1) + '/' + vldate.getDate() + '/' + vldate.getYear();
?>
<td class="hide">
<?= data[i][rid] ?>
</td>
<td>
<?= data[i][ldap] ?>
</td>
<td>
<?= data[i][aname] ?>
</td>
<td>
<?= data[i][lob] ?>
</td>
<td>
<?= [formattedDateVL] ?>
</td>
<td>
<?= data[i][rol] ?>
</td>
<td>
<?= data[i][tlapprov] ?>
</td>
<td>
<?= data[i][tlrem] ?>
</td>
<td>
<?= data[i][stat] ?>
</td>
<td>
<?= data[i][schedrem] ?>
</td>
<td class="lefttext">
<?= data[i][timeStamp] ?>
</td>
<? } ?>
</tr>
<? } ?>
</table>
<script>
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("vllist");
switching = true;
dir = "asc";
while (switching) {
switching = false;
rows = table.rows;
for (i = 1; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("TD")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
if (dir == "asc") {
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
shouldSwitch = true;
break;
}
} else if (dir == "desc") {
if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) {
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
switchcount ++;
} else {
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
</script>
What I would do is call the DATA into the table as normal... Then use JS to sort the records in the HTML table.
I think what you were trying to do is sort the data alphabetically first then display the data into the table . So rather put the data as is into the table, then use a sort Table function ..
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("myTable");
switching = true;
//Set the sorting direction to ascending:
dir = "asc";
/*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")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
/*check if the two rows should switch place,
based on the direction, asc or desc:*/
if (dir == "asc") {
if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
//if so, mark as a switch and break the loop:
shouldSwitch= true;
break;
}
} else if (dir == "desc") {
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;
//Each time a switch is done, increase this count by 1:
switchcount ++;
} else {
/*If no switching has been done AND the direction is "asc",
set the direction to "desc" and run the while loop again.*/
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
table {
border-spacing: 0;
width: 100%;
border: 1px solid #ddd;
}
th {
cursor: pointer;
}
th, td {
text-align: left;
padding: 16px;
}
tr:nth-child(even) {
background-color: #f2f2f2
}
<p><strong>Click the headers to sort the table.</strong></p>
<p>The first time you click, the sorting direction is ascending (A to Z).</p>
<p>Click again, and the sorting direction will be descending (Z to A):</p>
<table id="myTable">
<tr>
<!--When a header is clicked, run the sortTable function, with a parameter, 0 for sorting by names, 1 for sorting by country:-->
<th onclick="sortTable(0)">Name</th>
<th onclick="sortTable(1)">Country</th>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Italy</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Canada</td>
</tr>
</table>
Here's a simple solution for being able to sort in a spreadsheet by clicking on check boxes above the the header row.
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()=='Sheet1') {
if(e.range.rowStart==1 && e.range.columnStart<=sh.getLastColumn()) {
sh.getRange(3,1,sh.getLastRow()-1,sh.getLastColumn()).sort({column:e.range.columnStart,asc:(e.value=="TRUE")?true:false});
}
}
}
Here's what the Spreadsheet Might look like:
According to the Best Practices for UI with Apps Script, you should load your data asynchronously.
To show you how to do this + to create a proper sorting function for you, I have created the following sample Sheet:
Code.gs
function createSidebarWithHTML() {
var html = HtmlService.createHtmlOutputFromFile('Page')
.setTitle('My custom sidebar')
.setWidth(300);
SpreadsheetApp.getUi().showSidebar(html);
}
function getInitialData() {
var result = SpreadsheetApp.getActiveSpreadsheet().getDataRange().getValues();
result.shift(); //Removes header row from results
//Returns an array of arrays [rows, rows, ...] where rows = [column, column, column, ...]
return result;
}
Page.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<table id='mytable'>
<thead>
<tr>
<th colspan=4>POC VIEW</th>
</tr>
<tr>
<th colspan=4>Sample data!</th>
</tr>
<tr>
<th onclick=sort(0)>Header 1</th>
<th onclick=sort(1)>Header 2</th>
<th onclick=sort(2)>Header 3</th>
<th onclick=sort(3)>Header 4</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
var loadedData = null;
function loadTable(data) {
loadedData = data; //For caching of the received data.
var tablebody = document.querySelector('#mytable > tbody');
for (var i=0; i<data.length; i++) {
var newRow = document.createElement("tr");
for (var j=0; j<data[i].length; j++) {
var newCell = document.createElement("td");
var cellContent = document.createTextNode(data[i][j]);
newCell.appendChild(cellContent);
newRow.appendChild(newCell);
}
tablebody.appendChild(newRow);
}
}
function sort(row) {
var sortedData = loadedData;
//Sort data based on row Number
sortedData.sort(function(a,b) {
return a[row]-b[row];
});
var tablebody = document.querySelector('#mytable > tbody');
tablebody.innerHTML = ''; //Clear table body
for (var i=0; i<sortedData.length; i++) {
var newRow = document.createElement("tr");
for (var j=0; j<sortedData[i].length; j++) {
var newCell = document.createElement("td");
var cellContent = document.createTextNode(sortedData[i][j]);
newCell.appendChild(cellContent);
newRow.appendChild(newCell);
}
tablebody.appendChild(newRow);
}
}
//initialize data
function initialize() {
google.script.run.withSuccessHandler(loadTable).getInitialData();
}
initialize();
</script>
</body>
</html>

Using Java script to sort HTML table by appropriate column on column header click

I am trying to set up a HTML table that when you click on the column header it will sort the table by that column. My current solution works perfectly for the first column, its something I found on W3schools.
Edit: (Issue was the script comparing all the contained HTML in each TD, not just the displayed text)
But when I tried to generalise it with "n" instead of leaving a number in the java script for which column to sort, I can't seem to get it to take the correct value for n.
My plan was to use the code from W3schools (below) for sorting the first column, but insert a variable n to allow the same piece of code to sort multiple columns. I am trying to get the Java script to read n from the HTML section itself but i am not sure why it's not working.
This is my version of the W3schools code where I have tried to use n, this currently sorts the first column no matter which column header I click on.
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("mytable");
switching = true;
dir = "asc";
while (switching) {
switching = false;
rows = table.rows;
for (i = 1; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("TD")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
if (dir == "asc") {
if (x.innerHTML.toUpperCase() > y.innerHTML.toUpperCase()) {
shouldSwitch = true;
break;
}
} else if (dir == "desc") {
if (x.innerHTML.toUpperCase() < y.innerHTML.toUpperCase()) {
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
switchcount ++;
} else {
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
<table id="mytable">
<tr>
<th>
<div onclick="sortTable(0)">a</div>
</th>
<th>
<div onclick="sortTable(1)">b</div>
</th>
<th>
<div onclick="sortTable(2)">c</div>
</th>
</tr>
<tr>
<td>04718J00065</td>
<td>2100305513</td>
<td>10</td>
</tr>
<tr>
<td>29417J01131</td>
<td>2100305513</td>
<td>30</td>
</tr>
<tr>
<td>07416J01979</td>
<td>2100029648</td>
<td>0</td>
</tr>
</table>
I think what the issue is, is that the Java script isn't getting a value for n and it's defaulting to 0 which is why it sorts the first column no matter which header was clicked on. How can I get it to read n=0 from onclick="sortTable(0)", n=1 from onclick="sortTable(1)" etc?
I have found out what was causing the issue.
Using
(x.innerHTML.toUpperCase() > y.innerHTML.toUpperCase())
and
x = rows[i].getElementsByTagName("TD")[n];
y = rows[i + 1].getElementsByTagName("TD")[n];
compares everything inside that TD, not just the text that gets displayed. I had removed a <a></a> section from each TD when posting the code for this question trying to avoid posting code in too much detail and the link was pointing to files that shared a name with the string that was in the first column.
<table id="mytable">
<tr>
<th>
<div onclick="sortTable(0)">a</div>
</th>
<th>
<div onclick="sortTable(1)">b</div>
</th>
<th>
<div onclick="sortTable(2)">c</div>
</th>
</tr>
<tr>
<td>04718J00065</td>
<td>2100305513</td>
<td>10</td>
</tr>
<tr>
<td>29417J01131</td>
<td>2100305513</td>
<td>30</td>
</tr>
<tr>
<td>07416J01979</td>
<td>2100029648</td>
<td>0</td>
</tr>
</table>
<script>
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("mytable");
switching = true;
dir = "asc";
while (switching) {
switching = false;
rows = table.rows;
for (i = 1; i < (rows.length - 1); i++) {
shouldSwitch = false;
x = rows[i].getElementsByTagName("A")[n];
y = rows[i + 1].getElementsByTagName("A")[n];
if (dir == "asc") {
if (x.innerHTML.toUpperCase() > y.innerHTML.toUpperCase()) {
shouldSwitch = true;
break;
}
} else if (dir == "desc") {
if (x.innerHTML.toUpperCase() < y.innerHTML.toUpperCase()) {
shouldSwitch = true;
break;
}
}
}
if (shouldSwitch) {
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
switching = true;
switchcount ++;
} else {
if (switchcount == 0 && dir == "asc") {
dir = "desc";
switching = true;
}
}
}
}
</script>
My solution to this was just to swap "TD" in the script to "A" so it would compare inside the tag and not the link location itself. My changes to include "n" had worked as intended.

How to highlight a table row with the smallest value in a certain column using javascript

Supposed that I have a table like this on a webpage with the id ='table':
Name Age Money(USD) DATE
A 19 4 2019-03-11 16:15:35
B 20 0 2019-03-11 16:16:37
C 27 3 2019-03-13 04:15:43
D 34 0 2019-03-13 04:16:57
Could you help me find the FIRST SMALLEST VALUE IN THE MONEY COLUMN, which is 0 for B in the Column1 and HIGHLIGHT the whole table row for B, using javascript without using any library and any button onClicking?
Note: I have searched around and just been unlucky enough to find the correct answer to my problem.
Thanks.
UPDATE:I just got a piece of javacript like this to get the first smallest value and print it out, but not be able to highlight the whole row with it
var table = document.getElementById("table"), minVal;
for(var i = 1; i < table.rows.length; i++)
{
// if its the first row get the value
if(i === 1){minVal = table.rows[i].cells[2].innerHTML; }
// test with the other values
else if(minVal > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2].innerHTML;
}
}
document.getElementById("val").innerHTML = " Minimum Value = "+minVal;
console.log(maxVal);
var table = document.getElementById("table"), minVal, minI;
for(var i = 1; i < table.rows.length; i++){
if(i === 1){
minVal = table.rows[i].cells[2].innerHTML;
}
else if(minVal > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2].innerHTML;
minI = i;
}
}
table.rows[i].cells[2].innerHTML = '<span style="background:red">' + table.rows[minI].cells[2].innerHTML + '</span>';
Something like that.
var table = document.getElementById("table");
var minVal = undefined;
for(var i = 1; i < table.rows.length; i++)
{
if(i === 1){
minVal = table.rows[i].cells[2];
}
else if(minVal.innerHTML > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2];
}
}
minVal.parentElement.style.background="yellow";
There are two things you need to do:
Convert innerHTML to a number using +
Keep track of the row number while looping.
This is the code
var table = document.getElementById("table"), minVal;
let minRow = 1;
for(var i = 1; i < table.rows.length; i++)
{
// if its the first row get the value
if(i === 1){
minVal = +table.rows[i].cells[2].innerHTML;
}
// test with the other values
else if(minVal > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2].innerHTML;
minRow = i;
}
}
let row = table.rows[minRow];
row.style.backgroundColor = 'red';
This simply keeps track of the minimum row, and lets you hang your formatting off of that:
const highlightLowest = () => {
var rows = table.rows;
var minRow = rows[0]
for (var i = 1; i < rows.length; i++){
rows[i].classList.remove('highlight')
if (Number(rows[i].cells[2].innerHTML) < Number(minRow.cells[2].innerHTML)) {
minRow = rows[i]
}
}
minRow.classList.add('highlight')
}
tr.highlight td {background-color: yellow}
<table id="table">
<tr><td>A</td><td>19</td><td>4</td><td>2019-03-11 16:15:35</td></tr>
<tr><td>B</td><td>20</td><td>0</td><td>2019-03-11 16:16:37</td></tr>
<tr><td>C</td><td>27</td><td>3</td><td>2019-03-13 04:15:43</td></tr>
<tr><td>D</td><td>34</td><td>0</td><td>2019-03-13 04:16:57</td></tr>
</table>
<hr />
<button onClick="highlightLowest()">Highlight</button>
Here you go. The function 'highlight' takes the column that you want to base your highlighting upon as an argument.
// Get your table's headers
headers = document.querySelectorAll('#table tbody tr th')
// Get your table's headers
rows = document.querySelectorAll('#table tbody tr')
// Declaring function that takes wanted column as argument
highlight = (colName) =>{
let min = 0;
for(i=0;i<headers.length;i++){
if(headers[i].innerText == colName){
for(j=1;j<rows.length;j++){
value = parseInt(rows[j].children[i].innerHTML);
if(j == 1){
min = value;
}
if(value < min){
rows[j].style.backgroundColor = "yellow"
break;
}
}
}
}
}
<table id="table">
<tbody><tr>
<th>Test 1</th>
<th>Test 2</th>
<th>Test 3</th>
</tr>
<tr>
<td>7</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>3</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>12</td>
<td>1</td>
<td>5</td>
</tr>
<tr>
<td>15</td>
<td>89</td>
<td>4</td>
</tr>
<tr>
<td>3</td>
<td>6</td>
<td>6</td>
</tr>
<tr>
<td>2</td>
<td>4</td>
<td>8</td>
</tr>
</tbody></table>
<input type='text' id='col'>
<button onclick=highlight(document.getElementById('col').value)>Highlight based on input column</button>

Categories