Sort Table incorporated in GAS - javascript

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.

Related

Sorting Table with javascript

I have a simple table in HTML like this :
<table id="myTable">
<thead>
<tr>
<th class="pointer" onClick="sortTable()">Number</th>
<th>Example3</th>
<th>Example2</th>
<th>Example1</th>
</tr>
</thead>
<tbody>
<tr>
<td>101</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-01</td>
</tr>
<tr>
<td>102</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-02</td>
</tr>
</tbody>
</table>
and function for sorting this table in javascript but it's not working. I would like to sort the table descending by Column number. How to fix this? I would like also to add an arrow next to the column name to
call function by clicking the arrow
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 + 3].getElementsByTagName("TD")[0];
//check if the two rows should switch place:
if (Number(x.innerHTML) > Number(y.innerHTML)) {
//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 + 3], rows[i]);
switching = true;
}
}
}
Why switch with rows[i + 3] and not rows[i + 1]?
Why break the loop, and don't continue until the end?
function sortTable() {
var table, rows, switching, x, y;
table = document.getElementById("myTable");
/*Make a loop that will continue until
no switching has been done:*/
do {
//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 (var i = 1; i < (rows.length - 1); i++) {
//start by saying there should be no switching:
/*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 (Number(x.innerHTML) > Number(y.innerHTML)) {
//if so, mark as a switch
switching = true;
rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
rows = table.rows;
}
}
// run until no switches
} while (switching)
}
<table id="myTable">
<thead>
<tr>
<th class="pointer" onClick="sortTable()">Number</th>
<th>Example3</th>
<th>Example2</th>
<th>Example1</th>
</tr>
</thead>
<tbody>
<tr>
<td>101</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-01</td>
</tr>
<tr>
<td>102</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-02</td>
</tr>
<tr>
<td>100</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-00</td>
</tr>
</tbody>
</table>
If you had read little bit more the page you were on (https://www.w3schools.com/howto/howto_js_sort_table.asp) , you could find the answer of this question.
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 id="myTable">
<thead>
<tr>
<th class="pointer" onClick="sortTable(0)">Number</th>
<th>Example3</th>
<th>Example2</th>
<th>Example1</th>
</tr>
</thead>
<tbody>
<tr>
<td>101</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-01</td>
</tr>
<tr>
<td>102</td>
<td>TOM</td>
<td>Not Working</td>
<td>AUTOMAT-02</td>
</tr>
</tbody>
</table>
Here associated fiddle : https://jsfiddle.net/Louf0sc7/

How can i delete one row from a Table, which is saved in localStorage?

My Problem is, that i can only delete the full Content. By i need to delete a Row i selected.
I tried this:
function addData(){
arr.push({
name:document.getElementById('name').value,
datum:document.getElementById('datum').value,
start:document.getElementById('start').value,
ziel:document.getElementById('ziel').value,
hinfahrt:document.getElementById('hinfahrt').value,
ruckfahrt:document.getElementById('ruckfahrt').value,
zuzahlung:document.getElementById('zuzahlung').value
});
localStorage.setItem("localData",JSON.stringify(arr)); <---------
}
function deleteOne(){
var content = localStorage.getItem("localData");
localStorage.removeItem(JSON.stringify(arr[1]));
localStorage.removeItem(content);
}
The Informations are in a array. And the Key is "localData". How can i especial target one Row?
The checkpoint marks the deleting row:
Front
EDIT
I tried to implement, what you say. But i have this Problem. Cant remove from Storage. Here is my full Code. The Problem is in the Method
deleteOne() the Value for XXX. Hope you can understand my Problem.
var rowId = 0;
var testcounter;
function deleteMoreRows(tableID) {
var table = document.getElementById(tableID);
var rowCount = table.rows.length;
var selectedRows = getCheckedBoxes();
selectedRows.forEach(function (currentValue) {
deleteRowByCheckboxId(currentValue.id);
});
}
function getRowId() {
rowId += 1;
return rowId;
}
function getRowIdsFromElements($array) {
var arrIds = [];
$array.forEach(function (currentValue, index, array) {
arrIds.push(getRowIdFromElement(currentValue));
});
return arrIds;
}
function getRowIdFromElement($el) {
return $el.id.split('delete')[1];
}
function getCheckedBoxes() {
var inputs = document.getElementsByTagName("input");
var checkboxesChecked = [];
for (var i = 0; i < inputs.length; i++) {
// And stick the checked ones onto an array...
if (inputs[i].checked) {
checkboxesChecked.push(inputs[i]);
}
}
return checkboxesChecked.length > 0 ? checkboxesChecked : null;
}
function deleteRowByCheckboxId(CheckboxId) {
var checkbox = document.getElementById(CheckboxId);
var row = checkbox.parentNode.parentNode; //box, cell, row, table
var table = row.parentNode;
while (table && table.tagName != 'TABLE')
table = table.parentNode;
if (!table) return;
table.deleteRow(row.rowIndex);
}
function myFunction() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("search");
filter = input.value.toUpperCase();
table = document.getElementById("tbl_id");
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) {
// Hide the row initially.
tr[i].style.display = "none";
td = tr[i].getElementsByTagName("td");
for (var j = 0; j < td.length; j++) {
cell = tr[i].getElementsByTagName("td")[j];
if (cell) {
if (cell.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
break;
}
}
}
}
}
function sortTable(n) {
var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
table = document.getElementById("tbl_id");
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;
}
}
}
}
function sortTableByAdding() {
var table, rows, switching, i, x, y, shouldSwitch;
table = document.getElementById("tbl_id");
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")[1];
y = rows[i + 1].getElementsByTagName("TD")[1];
//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;
}
}
}
var arr = new Array();
//form onsubmit
function addData() {
getData();
arr.push({
name: document.getElementById('name').value,
datum: document.getElementById('datum').value,
start: document.getElementById('start').value,
ziel: document.getElementById('ziel').value,
hinfahrt: document.getElementById('hinfahrt').value,
ruckfahrt: document.getElementById('ruckfahrt').value,
zuzahlung: document.getElementById('zuzahlung').value
});
localStorage.setItem("localData", JSON.stringify(arr));
showData();
}
function getData() {
var str = localStorage.getItem("localData");
if (str != null) {
arr = JSON.parse(str);
}
}
function deleteData() {
localStorage.clear();
}
function deleteOne() {
var inhalt = localStorage.getItem("localData");
var tmp = JSON.parse(inhalt);
localStorage.removeItem("localData");
tmp.splice(**XXX**, 1);
localStorage.setItem("localData", JSON.stringify(tmp));
}
function showData() {
getData();
var table = document.getElementById('tbl_id');
var x = table.rows.length;
while (--x) {
table.deleteRow(x);
}
for (i = 0; i < arr.length; i++) {
var inputname = document.getElementById('name').value;
var inputdatum = document.getElementById('datum').value;
var inputstart = document.getElementById('start').value;
var inputziel = document.getElementById('ziel').value;
var inputhinfahrt = document.getElementById('hinfahrt').value;
var inputruckfahrt = document.getElementById('ruckfahrt').value;
var inputzuzahlung = document.getElementById('zuzahlung').value;
var row = table.insertRow();
var rowBox = row.insertCell(0);
var userName = row.insertCell(1);
var userDatum = row.insertCell(2);
var userStart = row.insertCell(3);
var userZiel = row.insertCell(4);
var userHinfahrt = row.insertCell(5);
var userRuckfahrt = row.insertCell(6);
var userZuzahlung = row.insertCell(7);
var checkbox = row.insertCell(8);
rowBox.innerHTML = '<input type="checkbox" id="delete' + getRowId() + '">';
userName.innerHTML = arr[i].name;
userDatum.innerHTML = arr[i].datum;
userStart.innerHTML = arr[i].start;
userZiel.innerHTML = arr[i].ziel;
userHinfahrt.innerHTML = arr[i].hinfahrt;
userRuckfahrt.innerHTML = arr[i].ruckfahrt;
userZuzahlung.innerHTML = arr[i].zuzahlung;
}
sortTableByAdding();
}
HTML
<body>
<input id="name" placeholder="Name" size="12" required>
<input id="datum" name="semdate" type="date" required>
<input id="start" placeholder="Start" size="12" required>
<input id="ziel" placeholder="Ziel" size="12" required>
<input id="hinfahrt" type="checkbox">Hinfahrt
<input id="ruckfahrt" type="checkbox">Rückfahrt
<input id="zuzahlung" placeholder="Zuzahlung" size="12">
<br>
<input type="button" id="mysubmit" value="Add" onClick="addData()">
<input type="button" id="delete" value="Delete"
onClick="deleteMoreRows('tbl_id')">
<input type="text" id="search" onkeyup="myFunction()" placeholder="Suche"
title="Type in a name">
<br>
<br>
<table id="tbl_id" style="text-align:center" align="center" valign="top">
<thead>
<tr>
<th style="width:200px;">Löschen</th>
<th onclick="sortTable(1)" style="width:200px;">Name</th>
<th onclick="sortTable(2)" style="width:200px;">Datum</th>
<th onclick="sortTable(3)" style="width:200px;">Start</th>
<th onclick="sortTable(4)" style="width:200px;">Ziel</th>
<th onclick="sortTable(5)" style="width:200px;">Hinfahrt</th>
<th onclick="sortTable(6)" style="width:200px;">Rückfahrt</th>
<th onclick="sortTable(7)" style="width:200px;">Zuzahlung</th>
</tr>
</thead>
<script>
showData();
</script>
<button onclick="deleteData()">!!!Clear Storage!!!</button>
<button onclick="deleteEinzel()">test</button>
</body>
You could use a data structure which allows you to target values by key. One option is to use an object instead of an array and remove/add the rows by their corresponding key.
// pass the id as a parameter to target the row
function addData(rowId) {
let storageTmp = JSON.parse(localStorage.getItem("storage"));
storageTmp = {
// ... -> spread operator
// add content of storage
...storageTmp,
// add new row
rowId: {
name: 'name',
datum: 'datum'
}
}
// overwrite storage variable
localStorage.setItem("storage", JSON.stringify(storageTmp));
}
// pass the id as a parameter to target the row
function deleteOne(rowId) {
const storageTmp = JSON.parse(localStorage.getItem("storage"));
// remove property
delete storageTmp.rowId;
localStorage.setItem("storage", JSON.stringify(storageTmp));
}
Another one would be to use a Map which got introduced by ECMA 6.
Save the content in a Json object.
var tmp = JSON.parse(content);
then delete the full content of the local storage
localStorage.removeItem("localdata");
then delete your line
tmp.splice(row, 1);
and finally throw data in local storage
localStorage.setItem("localData",JSON.stringify(tmp));
You have to retrieve the entry from the local storage, delete the value you want to delete and then write it to the local storage again.

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.

Sort table by sub-string

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;
}
}
}
}

Categories