The table that will populate depending on the selected dropdown element. There is an HTML code (I didn’t insert a line with dropdown and image)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="PlaneTable" class="table table-bordered">
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">450</td>
<td style="width: 15%">487</td>
<td style="width: 15%">450</td>
<td style="width: 15%">600</td>
</tr>
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">580</td>
<td style="width: 15%">490</td>
<td style="width: 15%">543</td>
<td style="width: 15%">742</td>
</tr>
<tr>
<td style="width: 20%">Climb</td>
<td style="width: 15%">52</td>
<td style="width: 15%">34</td>
<td style="width: 15%">23</td>
<td style="width: 15%">43</td>
</tr>
</table
<!-- And script what set green color to best value and red color to worse -->
<script>
$("#PlaneTable tbody tr").each(function() {
var values = [];
var tds = $(this).find('td');
tds.each(function() {
if ($.isNumeric($(this).text())) {
values.push($(this).text());
}
});
var min = Math.min.apply(Math, values);
var max = Math.max.apply(Math,
values);
tds.each(function() {
if ($(this).text() == min) {
$(this).css('backgroundColor', 'red');
}
if ($(this).text() == max) {
$(this).css('backgroundColor', 'green');
}
});
});
</script>
Finally i have this
I need to change my script for the next requirements:
Some data, for example, "Climb" row better if it has a lower value. IMHO better apply a script to row, not to the table. Also, some rows should not be highlighting.
If I add a label "km/h". For example 450 km/h highlighting don't work. Need to fix
If <td> have concrete value "null" (int nullable type), it should not be highlighting anytime
Consider the following.
$(function() {
function getNum(s) {
var n = false;
if (s.length) {
n = parseInt(s, 10);
}
return n;
}
function getRowData(t) {
var r = [],
n;
$("td", t).each(function(i, el) {
n = getNum($(el).text());
if (i > 0 && n) {
r.push(n);
}
});
return r;
}
$("#PlaneTable tbody tr").each(function(ind, row) {
var values = getRowData($(row));
var min = Math.min.apply(Math, values);
var max = Math.max.apply(Math, values);
console.log(values, min, max);
if ($("td", row).eq(0).text() == "Climb") {
$(row).addClass("low");
} else {
$(row).addClass("high");
}
$("td", row).each(function(j, cell) {
if ($(cell).text().indexOf(min) == 0 && $(".min", row).length < 1) {
$(this).addClass("min");
}
if ($(cell).text().indexOf(max) == 0 && $(".max", row).length < 1) {
$(cell).addClass("max");
}
});
});
});
.high .min {
background-color: red;
}
.high .max {
background-color: green;
}
.low .min {
background-color: green;
}
.low .max {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="PlaneTable" class="table table-bordered">
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">450 km/h</td>
<td style="width: 15%">487 km/h</td>
<td style="width: 15%">450 km/h</td>
<td style="width: 15%">600 km/h</td>
</tr>
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">580 km/h</td>
<td style="width: 15%">490 km/h</td>
<td style="width: 15%">543 km/h</td>
<td style="width: 15%">742 km/h</td>
</tr>
<tr>
<td style="width: 20%">Climb</td>
<td style="width: 15%">52 km/h</td>
<td style="width: 15%">34 km/h</td>
<td style="width: 15%">23 km/h</td>
<td style="width: 15%"></td>
</tr>
</table>
References:
https://www.w3schools.com/jsref/jsref_indexof.asp
https://www.w3schools.com/jsref/jsref_parseint.asp
https://api.jquery.com/each/
Related
There is a table that will populate depending on the selected dropdown element. Here is the code (I didn’t insert a line with dropdown elements):
<table id="myPlaneTable" class="table table-bordered">
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">450</td>
<td style="width: 15%">487</td>
<td style="width: 15%">450</td>
<td style="width: 15%">600</td>
</tr>
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">580</td>
<td style="width: 15%">490</td>
<td style="width: 15%">543</td>
<td style="width: 15%">742</td>
</tr>
</table
Here's what it looks like
Since I was just starting to learn jQuery, I tried the following code, but it does not work
$("#myPlaneTable tbody tr.data-in-table").each(function () {
$(this).find('td').each(function (index) {
var currentCell = $(this);
var nextCell = $(this).next('td').length > 0 ? $(this).next('td') : null;
if (index%2==0&&nextCell && currentCell.text() !== nextCell.text()) {
currentCell.css('backgroundColor', 'red');
nextCell.css('backgroundColor', 'green');
}
});
});
The result I'm trying to get
Highlighting if only the best and worst value (not between)
If the data matches in several cells, it is necessary to highlight them too
If there is no data, the cell should be without highlighting
Data should be compared within one <tr>, since there will be several lines
You can store all the values of each row in an array.
Then, store the minimum and maximum values, and finally apply the color to each <td> if the value match.
$("#myPlaneTable tbody tr").each(function () {
var values = [];
var tds = $(this).find('td');
tds.each(function () {
if ($.isNumeric($(this).text())) {
values.push($(this).text());
}
});
var min = Math.min.apply(Math, values);
var max = Math.max.apply(Math, values);
tds.each(function () {
if ($(this).text() == min) {
$(this).css('backgroundColor', 'red');
}
if ($(this).text() == max) {
$(this).css('backgroundColor', 'green');
}
});
});
you have to loop through all Table Rows and Table cells, throw them together in an array and compare the numbers then for the lowest and highest.
I will give you 2 Solutions for the styling, first one (better choice) via seperate css file styling, second one via inline jQuery Styling.
Here is an working example how it can be solved:
https://jsfiddle.net/efmkr08t/1/
$('#myPlaneTable').find('tr').not(':first').each(function(index, tr) {
var cols = [];
$(tr).find('td').not(':first').each(function(index, td) {
if ($(td).text() === '') {
return;
}
cols[index] = Number($(td).text());
});
var max = Math.max.apply(null, cols);
var min = Math.min.apply(null, cols);
$(tr).find('td').not(':first').each(function(index, td) {
if (Number($(td).text()) === min) {
// the way you should use it (styling is via css)
$(td).addClass('min')
// inline css
// $(td).css('background', 'red');
}
if (Number($(td).text()) === max) {
// the way you should use it (styling is via css)
$(td).addClass('max')
// inline css
// $(td).css('background', 'green');
}
});
});
Here I'm using jQuery map and toggleClass()
$(function(){
$('#myPlaneTable tr').each(function(index, tr) {
max = Math.max.apply(Math,$('td:not(:first)', tr).map(function(index, td) {
return parseInt($(td).text());
}));
min = Math.min.apply(Math,$('td:not(:first)', tr).map(function(index, td) {
return parseInt($(td).text());
}));
$(this).find('td').each( function(){
$(this).toggleClass('best',parseInt($(this).text())==max).toggleClass('worst', parseInt($(this).text())==min)
});
});
});
.best{
background-color:green;
}
.worst{
background-color:red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myPlaneTable" class="table table-bordered">
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">450</td>
<td style="width: 15%">487</td>
<td style="width: 15%">450</td>
<td style="width: 15%">600</td>
</tr>
<tr>
<td style="width: 20%">Max speed</td>
<td style="width: 15%">580</td>
<td style="width: 15%">490</td>
<td style="width: 15%">543</td>
<td style="width: 15%">742</td>
</tr>
</table>
Each column filter, filters its own column, but when trying to filter another column, previous column filters are not remembered.
For example, in the given table: If I search "Basketball" as the sport, then want to narrow my results and search for a specific team in the "Team" column, my results from the "Sport" column are no longer included because the table has reset.
I want to make this usable regardless of the input fields and corresponding columns. So I could use it on multiple tables if need be. That is why I used:
// if data-label matches input name - run
if(cells[j].getAttribute('data-label').match(inputName)){
// do stuff
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Filter Table by Column</title>
<link rel="stylesheet" href="css/style.css
">
</head>
<body>
<table>
<thead>
<tr>
<td><input type="text" name="Player" placeholder="Player... "></td>
<td><input type="text" name="Sport" placeholder="Sport..."></td>
<td><input type="text" name="Team" placeholder="Team..."></td>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Player">Michael Jordan</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Chicago Bulls</td>
</tr>
<tr>
<td data-label="Player">Kobe Bryant</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Brett Favre</td>
<td data-label="Sport">Football</td>
<td data-label="Team">Greenbay Packers</td>
</tr>
<tr>
<td data-label="Player">Babe Ruth</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">New York Yankees</td>
</tr>
<tr>
<td data-label="Player">Tom Brady</td>
<td data-label="Sport">Football</td>
<td data-label="Team">New England Patriots</td>
</tr>
<tr>
<td data-label="Player">LeBron James</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Steph Curry</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Golden State Warriors</td>
</tr>
<tr>
<td data-label="Player">Jose Berrios</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Kirby Pucket</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Zach Parise</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
<tr>
<td data-label="Player">Jason Zucker</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
</tbody>
</table>
<script src="js/main.js"></script>
</body>
</html>
main.js
// Listen to all clicks on the document
document.addEventListener('keyup', function(e){
// if event doesn't match
if(!e.target.matches('input[type="text"]')) return;
// otherwise run
filterTable(e);
}, false);
// filter results
function filterTable(e){
let inputName = e.target.name;
let filter = e.target.value.toUpperCase();
let rows = document.querySelector('table tbody').rows;
// get each row
for(let i = 0; i < rows.length; i++){
// loop through each cell
let cells = rows[i].cells;
for(j = 0; j < cells.length; j++){
let rowContent = cells[j].textContent;
// if data-label matches input name - run
if(cells[j].getAttribute('data-label').match(inputName)){
// if rowContent inlcudes input - run
if(rowContent.toUpperCase().includes(filter)){
// show row
rows[i].style.display = "";
} else {
// hide row
rows[i].style.display = "none";
}
}
}
}
}
style.css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
height: 100%;
line-height: 1.5;
}
input {
padding: 8px;
border: 0;
border-bottom: 1px solid #ccc;
width: 100%;
}
input:focus {
outline: none;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
padding: 8px;
}
table td {
padding: 8px;
}
table tbody tr:hover {
background: #999;
}
Can be simplified with array of filters :
function filterTable() {
const query = q => document.querySelectorAll(q);
const filters = [...query('th input')].map(e => new RegExp(e.value, 'i'));
query('tbody tr').forEach(row => row.style.display =
filters.every((f, i) => f.test(row.cells[i].textContent)) ? '' : 'none');
}
<table>
<thead>
<tr>
<th><input onkeyup="filterTable()" placeholder="Player... "></th>
<th><input onkeyup="filterTable()" placeholder="Sport..."></th>
<th><input onkeyup="filterTable()" placeholder="Team..."></th>
</tr>
</thead>
<tbody>
<tr><td> Michael Jordan </td><td> Basketball </td><td> Chicago Bulls </td></tr>
<tr><td> Kobe Bryant </td><td> Basketball </td><td> LA Lakers </td></tr>
<tr><td> Brett Favre </td><td> Football </td><td> Greenbay Packers </td></tr>
<tr><td> Babe Ruth </td><td> Baseball </td><td> New York Yankees </td></tr>
<tr><td> Tom Brady </td><td> Football </td><td> New England Patriots </td></tr>
<tr><td> LeBron James </td><td> Basketball </td><td> LA Lakers </td></tr>
<tr><td> Steph Curry </td><td> Basketball </td><td> Golden State Warriors </td></tr>
<tr><td> Jose Berrios </td><td> Baseball </td><td> Minnesota Twins </td></tr>
<tr><td> Kirby Pucket </td><td> Baseball </td><td> Minnesota Twins </td></tr>
<tr><td> Zach Parise </td><td> Hockey </td><td> Minnesota Wild </td></tr>
<tr><td> Jason Zucker </td><td> Hockey </td><td> Minnesota Wild </td></tr>
</tbody>
</table>
You can add an event listener on when the user starts to type and then match the input with the element's value. For all the td elements, check for those which matches to the string input using .includes and then change the visibility of that element to hidden if it doesn't match if it does then make it visible.
Now to filter out Teams and Sport, just do the same for the next element and the previous because they are consecutive.
document.getElementsByName("Player")[0].onkeyup = function() {
let value = this.value
Array.from(document.querySelectorAll('td[data-label="Player"]')).forEach((ele) => {
if (value != '') {
ele.style.visibility = "visible" // first display all the elements then decide what to display and what not to.
if (ele.innerHTML.toLowerCase().includes(value.toLowerCase())) { // match the lower cased value so "B == b"
ele.style.visibility = "visible"
} else {
ele.style.visibility = "hidden"
ele.nextElementSibling.style.visibility = "hidden" // the teams
ele.nextElementSibling.nextElementSibling.style.visibility = "hidden" // the Sport
}
} else {
ele.style.visibility = "visible"
ele.nextElementSibling.style.visibility = "visible"
ele.nextElementSibling.nextElementSibling.style.visibility = "visible"
}
})
}
document.getElementsByName("Sport")[0].onkeyup = function() {
let value = this.value
Array.from(document.querySelectorAll('td[data-label="Sport"]')).forEach((ele) => {
if (value != '') {
ele.style.visibility = "visible"
if (ele.innerHTML.toLowerCase().includes(value.toLowerCase())) {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
} else {
ele.style.visibility = "hidden"
ele.previousElementSibling.style.visibility = "hidden"
}
} else {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
}
})
}
document.getElementsByName("Team")[0].onkeyup = function() {
let value = this.value
Array.from(document.querySelectorAll('td[data-label="Team"]')).forEach((ele) => {
if (value != '') {
ele.style.visibility = "visible"
if (ele.innerHTML.includes(value)) {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
ele.previousElementSibling.previousElementSibling.style.visibility = "visible"
} else {
ele.style.visibility = "hidden"
ele.previousElementSibling.style.visibility = "hidden"
ele.previousElementSibling.previousElementSibling.style.visibility = "hidden"
}
} else {
ele.style.visibility = "visible"
ele.previousElementSibling.style.visibility = "visible"
ele.previousElementSibling.previousElementSibling.style.visibility = "visible"
}
})
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
height: 100%;
line-height: 1.5;
}
input {
padding: 8px;
border: 0;
border-bottom: 1px solid #ccc;
width: 100%;
}
input:focus {
outline: none;
}
table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
padding: 8px;
}
table td {
padding: 8px;
}
table tbody tr:hover {
background: #999;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Filter Table by Column</title>
</head>
<body>
<table>
<thead>
<tr>
<td><input type="text" name="Player" placeholder="Player... "></td>
<td><input type="text" name="Sport" placeholder="Sport..."></td>
<td><input type="text" name="Team" placeholder="Team..."></td>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Player">Michael Jordan</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Chicago Bulls</td>
</tr>
<tr>
<td data-label="Player">Kobe Bryant</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Brett Favre</td>
<td data-label="Sport">Football</td>
<td data-label="Team">Greenbay Packers</td>
</tr>
<tr>
<td data-label="Player">Babe Ruth</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">New York Yankees</td>
</tr>
<tr>
<td data-label="Player">Tom Brady</td>
<td data-label="Sport">Football</td>
<td data-label="Team">New England Patriots</td>
</tr>
<tr>
<td data-label="Player">LeBron James</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">LA Lakers</td>
</tr>
<tr>
<td data-label="Player">Steph Curry</td>
<td data-label="Sport">Basketball</td>
<td data-label="Team">Golden State Warriors</td>
</tr>
<tr>
<td data-label="Player">Jose Berrios</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Kirby Pucket</td>
<td data-label="Sport">Baseball</td>
<td data-label="Team">Minnesota Twins</td>
</tr>
<tr>
<td data-label="Player">Zach Parise</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
<tr>
<td data-label="Player">Jason Zucker</td>
<td data-label="Sport">Hockey</td>
<td data-label="Team">Minnesota Wild</td>
</tr>
</tbody>
</table>
</body>
</html>
I use a object to store the different queries and then check each one when the input of any one change.
You can find a working demo here: https://codesandbox.io/s/suspicious-flower-80c8d
my js looks like this:
const queries = {};
const inputs = [...document.querySelectorAll("input")];
for (let input of inputs) {
input.addEventListener("input", e => {
const name = input.name;
queries[name] = input.value;
filterTable();
});
}
function filterRow(row, query, label) {
if (query) {
const text = row.querySelector('td[data-label="' + label + '"]').innerText;
if (text.toLowerCase().indexOf(query.toLowerCase()) < 0) {
row.style.display = "none";
}
}
}
function filterTable() {
document.querySelectorAll("tr").forEach((row, index) => {
if (index === 0) {
return;
}
row.style.display = "table-row";
for (let key in queries) {
filterRow(row, queries[key], key);
}
});
}
I have created table cells in html that have ids that increment by 1 for example: cell1, cell2, cell3, ......, cell100.
What I would like to do is loop through and get reference to each of these cells using a for loop because referencing them one by one won't be good pratice and will require alot of codes of line, instead of this;
var cell1 = document.getElementById('cell1');
var cell2 = document.getElementById('cell2');
var cell3 = document.getElementById('cell3');
......
var cell100 = document.getElementById('cell100');
Is it possible to do something like this?
for (i = 0; i<=100; i++) {
var cell+i = document.getElementById("cell"+i);
// then I can call individual cells and assign tasks to them something along the lines of;
cell1.addEventListener('input',function(){}
cell5.background = '#f5f5f5'
cell55.innerHTML = 'I am cell 55'
etc..
}
EDITED:
Incase it might be useful, I have 1 table that contains many cells of which some have ids and some don't. I would only like to reference the ones that do have ids.
you can use document.querySelectorAll with a wildcard
var slice = Array.prorotype.slice;
var selection = document.querySelectorAll("[id^=cell]");
slice.call(selection).forEach(function(item, index){
// here item is the table row and index is the iteration number of forEach
// to get the id
var id = item.id;
//to get the numerical value in id
var number_in_id = item.id.match(/\d+/g)[0];
})
document.querySelectorAll("[id^=cell]") selectects all elements that their id starts with the string cell if you want to make it specific for table td's you add document.querySelectorAll("td[id^=cell]")
may be you are looking for this
var grid = document.getElementById("grid");//grid is the id of the table
for (var i = 1, row; row = grid.rows[i]; i++)
row.cells[0].textContent = "";//content of the starts with row 1..2..3 and so one than cell[0] or cell[1] and so on.
It'd be good pratice to use classes, though;
In base of your loop, you can do it so to get the current element, but if you have an loop more longer than the amount of the elements id numbers sequence, then it will be returning errors.
var Cell=document.getElementById("cell"+i)
//you've your DOM element in the variable called Cell now
//the one error you did is in the variable name
//you used the + operator in the variable name;
That's equivalent to element with id "cell0" when it's the first execution time of the loop. Not too elegant, you've many other ways to do the same.
Yes, it is quite easy, see below.
var cells = [];
for (var i = 0; i <= 100; i++) {
cells[i] = document.getElementById("cell"+i);
// do stuff....
if( cells[55] ) {
cells[55].innerHTML = 'I am cell 55';
}
}
Consider you have a table with an ID as myTable.
Get the table with,,
var theTable = document.getElementById('myTable');
To get all <td>s you could do,
var cells = theTable.querySelectorAll('td');
Then do the looping part,
for(var i = 0; i < cells.length; i++){
if(cells[i].id && cells[i].id.indexOf('cell') != -1){ //added to get only the significant cells
//do your stuff
cells[i].addEventListener(function(){});
cells[i].innerHTML = 'Something';
}
}
I'm lazy and didn't want to hand code any table, so I made Demo 2:
A form that'll accept a number of rows and columns
Can create <tr> and append to a table (0 to 100 rows)
Can create <td> and append to a <tr>(0 to 100 columns)
Assigns a unique id to every <tr> and <td>
The id pattern allows a human reader to locate <tr>s and <td>s
Each id for the <td> are displayed in each cell.
There's also two arrays, one for the <tr>(rowX) and one for the <td>(colY). There's many powerful methods for Array and having those 2 arrays you could even make a two-dimensional array.
Concerning the OP's request specifically about an id for cells on a table (complete or partial), I am aware that you have a pre-made table, so I'll take the key lines that make it possible in Demo 2 to assign ids:
row.setAttribute('id', 'r' + r);// Each row will have a numbered id (ex. r0 is row 1)
col.setAttribute('id', 'r' + r + 'c' + c);// Each cell will have a numbered id representing it's location (ex. r3c0 is located on row 4 column 1)
Demo 1
This snippet is an adaptation of the code previously mentioned:
function oddRows() {
var rows = document.querySelectorAll('tr');
// rows is a NodeList (an array-like object).
// We can covert this NodeList into an Array.
var rowArray = Array.prototype.slice.call(rows);
//Either way, NodeList or Array should be iterated through a for loop (most common way to reiterate)
for (var i = 0; i < rowArray.length; i++) {
if (i % 2 === 1) {
console.log(i);
var odd = rowArray[i];
odd.style.display = "none";
//This filters and removes all odd numbered rows
}
}
return false;
}
function evenCols() {
var cols = document.querySelectorAll('td');
var colArray = Array.prototype.slice.call(cols);
for (var j = 0; j < colArray.length; j++) {
if (j % 2 === 0) {
console.log(j);
var even = colArray[j];
even.style.backgroundColor = "red";
//This filters even numbered <td> and colors the background red.
}
}
return false;
}
td {
border: 2px inset #777;
}
button {
margin: 20px 5px 10px;
}
<button id="btn1" onclick="oddRows();">Remove Odd Rows</button>
<button id="btn2" onclick="evenCols();">Mark Even Cols</button>
<table id="t1">
<tr id="r0" class="row">
<td id="r0c0" class="col">r0c0</td>
<td id="r0c1" class="col">r0c1</td>
<td id="r0c2" class="col">r0c2</td>
<td id="r0c3" class="col">r0c3</td>
<td id="r0c4" class="col">r0c4</td>
<td id="r0c5" class="col">r0c5</td>
<td id="r0c6" class="col">r0c6</td>
<td id="r0c7" class="col">r0c7</td>
<td id="r0c8" class="col">r0c8</td>
<td id="r0c9" class="col">r0c9</td>
</tr>
<tr id="r1" class="row">
<td id="r1c0" class="col">r1c0</td>
<td id="r1c1" class="col">r1c1</td>
<td id="r1c2" class="col">r1c2</td>
<td id="r1c3" class="col">r1c3</td>
<td id="r1c4" class="col">r1c4</td>
<td id="r1c5" class="col">r1c5</td>
<td id="r1c6" class="col">r1c6</td>
<td id="r1c7" class="col">r1c7</td>
<td id="r1c8" class="col">r1c8</td>
<td id="r1c9" class="col">r1c9</td>
</tr>
<tr id="r2" class="row">
<td id="r2c0" class="col">r2c0</td>
<td id="r2c1" class="col">r2c1</td>
<td id="r2c2" class="col">r2c2</td>
<td id="r2c3" class="col">r2c3</td>
<td id="r2c4" class="col">r2c4</td>
<td id="r2c5" class="col">r2c5</td>
<td id="r2c6" class="col">r2c6</td>
<td id="r2c7" class="col">r2c7</td>
<td id="r2c8" class="col">r2c8</td>
<td id="r2c9" class="col">r2c9</td>
</tr>
<tr id="r3" class="row">
<td id="r3c0" class="col">r3c0</td>
<td id="r3c1" class="col">r3c1</td>
<td id="r3c2" class="col">r3c2</td>
<td id="r3c3" class="col">r3c3</td>
<td id="r3c4" class="col">r3c4</td>
<td id="r3c5" class="col">r3c5</td>
<td id="r3c6" class="col">r3c6</td>
<td id="r3c7" class="col">r3c7</td>
<td id="r3c8" class="col">r3c8</td>
<td id="r3c9" class="col">r3c9</td>
</tr>
<tr id="r4" class="row">
<td id="r4c0" class="col">r4c0</td>
<td id="r4c1" class="col">r4c1</td>
<td id="r4c2" class="col">r4c2</td>
<td id="r4c3" class="col">r4c3</td>
<td id="r4c4" class="col">r4c4</td>
<td id="r4c5" class="col">r4c5</td>
<td id="r4c6" class="col">r4c6</td>
<td id="r4c7" class="col">r4c7</td>
<td id="r4c8" class="col">r4c8</td>
<td id="r4c9" class="col">r4c9</td>
</tr>
<tr id="r5" class="row">
<td id="r5c0" class="col">r5c0</td>
<td id="r5c1" class="col">r5c1</td>
<td id="r5c2" class="col">r5c2</td>
<td id="r5c3" class="col">r5c3</td>
<td id="r5c4" class="col">r5c4</td>
<td id="r5c5" class="col">r5c5</td>
<td id="r5c6" class="col">r5c6</td>
<td id="r5c7" class="col">r5c7</td>
<td id="r5c8" class="col">r5c8</td>
<td id="r5c9" class="col">r5c9</td>
</tr>
<tr id="r6" class="row">
<td id="r6c0" class="col">r6c0</td>
<td id="r6c1" class="col">r6c1</td>
<td id="r6c2" class="col">r6c2</td>
<td id="r6c3" class="col">r6c3</td>
<td id="r6c4" class="col">r6c4</td>
<td id="r6c5" class="col">r6c5</td>
<td id="r6c6" class="col">r6c6</td>
<td id="r6c7" class="col">r6c7</td>
<td id="r6c8" class="col">r6c8</td>
<td id="r6c9" class="col">r6c9</td>
</tr>
<tr id="r7" class="row">
<td id="r7c0" class="col">r7c0</td>
<td id="r7c1" class="col">r7c1</td>
<td id="r7c2" class="col">r7c2</td>
<td id="r7c3" class="col">r7c3</td>
<td id="r7c4" class="col">r7c4</td>
<td id="r7c5" class="col">r7c5</td>
<td id="r7c6" class="col">r7c6</td>
<td id="r7c7" class="col">r7c7</td>
<td id="r7c8" class="col">r7c8</td>
<td id="r7c9" class="col">r7c9</td>
</tr>
<tr id="r8" class="row">
<td id="r8c0" class="col">r8c0</td>
<td id="r8c1" class="col">r8c1</td>
<td id="r8c2" class="col">r8c2</td>
<td id="r8c3" class="col">r8c3</td>
<td id="r8c4" class="col">r8c4</td>
<td id="r8c5" class="col">r8c5</td>
<td id="r8c6" class="col">r8c6</td>
<td id="r8c7" class="col">r8c7</td>
<td id="r8c8" class="col">r8c8</td>
<td id="r8c9" class="col">r8c9</td>
</tr>
<tr id="r9" class="row">
<td id="r9c0" class="col">r9c0</td>
<td id="r9c1" class="col">r9c1</td>
<td id="r9c2" class="col">r9c2</td>
<td id="r9c3" class="col">r9c3</td>
<td id="r9c4" class="col">r9c4</td>
<td id="r9c5" class="col">r9c5</td>
<td id="r9c6" class="col">r9c6</td>
<td id="r9c7" class="col">r9c7</td>
<td id="r9c8" class="col">r9c8</td>
<td id="r9c9" class="col">r9c9</td>
</tr>
</table>
If ids seem too heavy and cumbersome, you can select any cell on a table by using the pseudo-selectors nth-child and nth-of-type.
Example:
Target:* You want the 3rd <td> on the 5th row to have red text.
CSS:
table tbody tr:nth-of-type(5) td:nth-of-type(3) { color: red; }
jQuery:
$("table tbody tr:nth-of-type(5) td:nth-of-type(3)").css('color', 'red');
JavaScript:
var tgt = document.querySelector("table tbody tr:nth-of-type(5) td:nth-of-type(3)");
tgt.style.color = "red";
*Assuming that the target element has a table with a <tbody>
Demo 2
fieldset {
width: 50vw;
height: 55px;
margin: 10px auto;
padding: 3px;
}
input {
width: 40px;
height: 20px;
margin: 5px 10px;
}
table {
table-layout: fixed;
border-collapse: collapse;
border: 3px ridge #666;
width: 50vw;
height: 50vh;
margin: 20px auto;
}
td {
height: 20px;
width: 20px;
border: 1px inset grey;
font-size: 8px;
}
<fieldset>
<legend>Rows & Columns</legend>
<input id="rows" type="number" min="0" max="100" />
<input id="cols" type="number" min="0" max="100" />
<button id="btn1">Build</button>
</fieldset>
<table id="t1"></table>
<script>
var t1 = document.getElementById('t1');
var rows = document.getElementById('rows');
var cols = document.getElementById('cols');
var btn1 = document.getElementById('btn1');
btn1.addEventListener('click', function(e) {
var R = rows.value;
var C = cols.value;
var rowX = [];
var colY = [];
for (var r = 0; r < R; r++) {
var row = document.createElement('tr');
row.setAttribute('id', 'r' + r);// Each row will have a numbered id (ex. r0 is row 1)
row.classList.add('row');
rowX.push(row);
t1.appendChild(row)
for (var c = 0; c < C; c++) {
var col = document.createElement('td');
col.setAttribute('id', 'r' + r + 'c' + c);// Each cell will have a numbered id representing it's location (ex. r3c0 is located on row 4 column 1)
col.innerHTML = col.id;
col.classList.add('col');
colY.push(col);
row.appendChild(col);
}
}
}, false);
</script>
I have multiple tbody in a table which some of span columns and rows. And then I got a jQuery code to sort this tbody based on the th.data- click.
In the first th column when it is clicked it will sort correctly. However, in the second th column when it is clicked it does not sort the tbody.
Here is the snippet :
var table = $('table'),
th = table.find('thead th'),
tbody = table.find('tbody');
$(th).on('click', function() {
$(th).removeClass();
var index = this.cellIndex,
sortType = $(this).data('sort'),
sortDir = $(this).data('dir') || 'asc';
var that = $(this);
$('table').find('tbody').slice().sort(function(a, b) {
var dataTH = that.data('class');
//alert(dataTH);
if(dataTH == 'number')
{
//alert("hi this is a number");
var aText = $(a).find('td.sortNum:eq(' + index + ')').text(),
bText = $(b).find('td.sortNum:eq(' + index + ')').text();
}
else if(dataTH == 'department')
{
//alert("hi this is a department");
var aText = $(a).find('td.depart:eq(' + index + ')').text(),
bText = $(b).find('td.depart:eq(' + index + ')').text();
}
if (sortDir == 'desc') {
temp = aText;
aText = bText;
bText = temp;
}
if (sortType == 'string') {
return aText.localeCompare(bText);
}
else {
return +aText - +bText;
}
})
.appendTo('table');
$(this).data('dir', sortDir == 'asc' ? 'desc' : 'asc');
$(this).removeClass().addClass('sort-' + sortDir);
});
table {
border-collapse: collapse;
width: 400px;
}
th, td {
padding: 5px;
border: 1px #DDD solid;
}
.sort-asc:after,
.sort-desc:after {
content: '▲';
font-size: 12px;
}
.sort-desc:after {
content: '▼';
}
<table>
<thead>
<tr>
<th data-sort="number" data-class="number" >No</th>
<th data-sort="number" data-class="department" >Department</th>
<th data-sort="number">Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2" class="sortNum">1</td>
<td class="depart">20</td>
<td>20</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">2</td>
<td class="depart">30</td>
<td>25</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">3</td>
<td class="depart">40</td>
<td>50</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">4</td>
<td class="depart">50</td>
<td>15</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
<tbody>
<tr>
<td rowspan="2" class="sortNum">5</td>
<td class="depart">60</td>
<td>32</td>
</tr>
<tr>
<td colspan="2" style="text-align:center">VTP</td>
</tr>
</tbody>
</table>
You do not need the :eq Selector since you are referencing the Cells by css class. It does work in the first Column because the cell index is zero. What you are essentially saying in the selector $(a).find('td.sortNum:eq(' + index + ')') is "give me the list of td's with the class 'sortNum' and of that list the element at position index. But the first condition of the Selector - td.sortNum - will only return one element.
To make your sorting work again for the second column you could get rid of the :eq part
if(dataTH == 'number')
{
//alert("hi this is a number");
var aText = $(a).find('td.sortNum').text(),
bText = $(b).find('td.sortNum').text();
}
else if(dataTH == 'department')
{
//alert("hi this is a department");
var aText = $(a).find('td.depart').text(),
bText = $(b).find('td.depart').text();
}
see also http://jsfiddle.net/doc_snyder/Lvvmow8g/1/
I have the following table:
<table border="0" cellspacing="0" cellpadding="0" id="table1">
<tbody>
<tr>
<th onclick="sortTable(0, this); return false;" class="sort-up" order="-1">ColumnA</th>
<th style="width: 12em;" onclick="sortTable(1, this); return false;" class="sort-none">ColumnB</th>
<th style="width: 9em;" onclick="sortTable(2, this); return false;" class="sort-none">ColumnC</th>
<th style="width: 10em;" onclick="sortTable(3, this); return false;" class="sort-none">ColumnD</th>
<th style="width: 6em;">ColumnE</th>
</tr>
<tr id="tr217E9B6C" type="root" level="217E9B6C" depth="0">
<td class="evenListRow" id="nocenter">
<div class="tier1">Root A</div>
</td>
<td class="evenListRow">1</td>
<td class="evenListRow">2</td>
<td class="evenListRow">3</td>
<td class="evenListRow">4</a>
</td>
</tr>
<tr id="tr217E9B6C-6E781501" type="sub" level="217E9B6C-6E781501" depth="1">
<td class="oddListRow" id="nocenter">
<div class="tier2">Sub A</div>
</td>
<td class="oddListRow">5</td>
<td class="oddListRow">6</td>
<td class="oddListRow">7</td>
<td class="oddListRow">8</td>
</tr>
<tr id="tr217E9B6C-852AB6E5" type="sub" level="217E9B6C-852AB6E5" depth="1">
<td class="evenListRow" id="nocenter">
<div class="tier2">Sub B</div>
</td>
<td class="evenListRow">9</td>
<td class="evenListRow">10</td>
<td class="evenListRow">11</td>
<td class="evenListRow">12</td>
</tr>
<tr id="tr2BE7EAFE" type="root" level="2BE7EAFE" depth="0">
<td class="evenListRow" id="nocenter">
<div class="tier1">Root B</div>
</td>
<td class="evenListRow">13</td>
<td class="evenListRow">14</td>
<td class="evenListRow">15</td>
<td class="evenListRow">16</td>
</tr>
<tr id="tr2BE7EAFE-49A04568" type="sub" level="2BE7EAFE-49A04568" depth="1">
<td class="oddListRow" id="nocenter">
<div class="tier2">Sub C</div>
</td>
<td class="oddListRow">17</td>
<td class="oddListRow">18</td>
<td class="oddListRow">19</td>
<td class="oddListRow">20</td>
</tr>
<tr id="tr2BE7EAFE-DAE218A5" type="sub" level="2BE7EAFE-DAE218A5" depth="1">
<td class="evenListRow" id="nocenter">
<div class="tier2">Sub D</div>
</td>
<td class="evenListRow">21</td>
<td class="evenListRow">22</td>
<td class="evenListRow">23</td>
<td class="evenListRow">24</td>
</tr>
<tr id="tr4FFACE4A" type="root" level="4FFACE4A" depth="0">
<td class="oddListRow" id="nocenter">
<div class="tier1">Root C</div>
</td>
<td class="oddListRow">25</td>
<td class="oddListRow">26</td>
<td class="oddListRow">27</td>
<td class="oddListRow">28</td>
</tr>
<tr id="tr4FFACE4A-B9A443CA" type="sub" level="4FFACE4A-B9A443CA" depth="1">
<td class="evenListRow" id="nocenter">
<div class="tier2">Sub E</div>
</td>
<td class="evenListRow">29</td>
<td class="evenListRow">30</td>
<td class="evenListRow">31</td>
<td class="evenListRow">32</td>
</tr>
</tbody>
</table>
And I want to sort it, first by the "root" then by the "sub" items, which would mean that Root A will always have its Sub A, Sub B under it (sorted as well, but under it)
I used the following code which works on only on the "sub items", I cannot get it to work by doing a "mix", i.e. top and sub (separately sorted)
function sortTable(column, thisrow) {
var order = thisrow.getAttribute('order');
if (!order) {
order = 1;
}
var tbl = document.getElementById("table1").tBodies[0];
if (!tbl) {
return;
}
if (previousSortColumn && previousSortColumn.innerHTML != thisrow.innerHTML) {
previousSortColumn.setAttribute('class', 'sort-none');
}
previousSortColumn = thisrow;
var store = [];
/* Build a store object that has every element in the table, we will use this to sort */
for(var rowpos=1, len=tbl.rows.length; rowpos<len; rowpos++) { // skip row #1 as it is the header
var row = tbl.rows[rowpos];
var i_textContent = row.cells[column].textContent;
while(i_textContent.indexOf(' ') != -1) { // remove spaces
i_textContent = i_textContent.replace(' ', '');
}
var sortnr = i_textContent;
var type = row.getAttribute('type');
var level = row.getAttribute('level');
var depth = row.getAttribute('depth');
store.push({sortnr: sortnr, row:row, storelength:store.length, type:type, level:level, depth:depth});
}
/* We sort first roots then the elements under it */
store.sort(function(x,y) {
var xtype = x['type'];
var ytype = y['type'];
var result;
if (xtype == 'root' && ytype == 'root')
{
result = x['sortnr'].localeCompare(y['sortnr']);
} else {
return 0;
}
if (order == 1) {
return result;
} else {
return -1 * result;
}
});
/* We sort the elements under it */
store.sort(function(x,y) {
var xtype = x['type'];
var ytype = y['type'];
var xlevel = x['level'];
var ylevel = y['level'];
if (xlevel.lastIndexOf('-') > 0) {
xlevel = xlevel.substring(0, xlevel.lastIndexOf('-'));
}
if (ylevel.lastIndexOf('-') > 0) {
ylevel = ylevel.substring(0, ylevel.lastIndexOf('-'));
}
if (xlevel != ylevel || xtype == 'root' || ytype == 'root')
{
return x['storelength'] - y['storelength']; // return order inside array
}
var result = x['sortnr'].localeCompare(y['sortnr']);
if (order == 1) {
return result;
} else {
return -1 * result;
}
});
for(var i=0; i < store.length; i++) {
tbl.appendChild(store[i]['row']);
}
store = null;
}
Update 1:
Clicking once on 'ColumnB' would not affect the table (a bit of a bad example on my part), as the information is already sorted in the correct order, however another click should sort everything in reverse order
So both the Roots would be in reverse other, Root C, Root B, Root A, as well their sub items, Sub D before Sub C, ...
<table border="0" cellspacing="0" cellpadding="0" id="table1">
<tbody>
<tr>
<th onclick="sortTable(0, this); return false;" class="sort-up" order="-1">ColumnA</th>
<th style="width: 12em;" onclick="sortTable(1, this); return false;" class="sort-none">ColumnB</th>
<th style="width: 9em;" onclick="sortTable(2, this); return false;" class="sort-none">ColumnC</th>
<th style="width: 10em;" onclick="sortTable(3, this); return false;" class="sort-none">ColumnD</th>
<th style="width: 6em;">ColumnE</th>
</tr>
<tr id="tr4FFACE4A" type="root" level="4FFACE4A" depth="0">
<td class="oddListRow" id="nocenter">
<div class="tier1">Root C</div>
</td>
<td class="oddListRow">25</td>
<td class="oddListRow">26</td>
<td class="oddListRow">27</td>
<td class="oddListRow">28</td>
</tr>
<tr id="tr4FFACE4A-B9A443CA" type="sub" level="4FFACE4A-B9A443CA" depth="1">
<td class="evenListRow" id="nocenter">
<div class="tier2">Sub E</div>
</td>
<td class="evenListRow">29</td>
<td class="evenListRow">30</td>
<td class="evenListRow">31</td>
<td class="evenListRow">32</td>
</tr>
<tr id="tr2BE7EAFE" type="root" level="2BE7EAFE" depth="0">
<td class="evenListRow" id="nocenter">
<div class="tier1">Root B</div>
</td>
<td class="evenListRow">13</td>
<td class="evenListRow">14</td>
<td class="evenListRow">15</td>
<td class="evenListRow">16</td>
</tr>
<tr id="tr2BE7EAFE-DAE218A5" type="sub" level="2BE7EAFE-DAE218A5" depth="1">
<td class="evenListRow" id="nocenter">
<div class="tier2">Sub D</div>
</td>
<td class="evenListRow">21</td>
<td class="evenListRow">22</td>
<td class="evenListRow">23</td>
<td class="evenListRow">24</td>
</tr>
<tr id="tr2BE7EAFE-49A04568" type="sub" level="2BE7EAFE-49A04568" depth="1">
<td class="oddListRow" id="nocenter">
<div class="tier2">Sub C</div>
</td>
<td class="oddListRow">17</td>
<td class="oddListRow">18</td>
<td class="oddListRow">19</td>
<td class="oddListRow">20</td>
</tr>
<tr id="tr217E9B6C" type="root" level="217E9B6C" depth="0">
<td class="evenListRow" id="nocenter">
<div class="tier1">Root A</div>
</td>
<td class="evenListRow">1</td>
<td class="evenListRow">2</td>
<td class="evenListRow">3</td>
<td class="evenListRow">4</a>
</td>
</tr>
<tr id="tr217E9B6C-852AB6E5" type="sub" level="217E9B6C-852AB6E5" depth="1">
<td class="evenListRow" id="nocenter">
<div class="tier2">Sub B</div>
</td>
<td class="evenListRow">9</td>
<td class="evenListRow">10</td>
<td class="evenListRow">11</td>
<td class="evenListRow">12</td>
</tr>
<tr id="tr217E9B6C-6E781501" type="sub" level="217E9B6C-6E781501" depth="1">
<td class="oddListRow" id="nocenter">
<div class="tier2">Sub A</div>
</td>
<td class="oddListRow">5</td>
<td class="oddListRow">6</td>
<td class="oddListRow">7</td>
<td class="oddListRow">8</td>
</tr>
</tbody>
</table>
I solved your problem. I did reorganize the code to make it a lot more readable. Most of the logic is what you provided, i just added small bits. And btw, you have duplicate id references on id="nocenter" in your html.
Here is a working jsfiddle of my solution. The HTML is exactly the one you provided , with errors and all and no listener on column E. This js fiddle version has some more subs on root A. You can play with it as you will (add extra data). Summary of the code comes after it in the answer.
Update - taken your new input data in the comments , i updated the jsfiddle it would seem i kept the root in place, and it jumped out of subset. It was a matter of changing 1 line in sorting the subs. The new fiddle.
var ASC = 1;
var DESC = -1;
var SORTNR_INDEX = 0;
var LOWER = 1;
var UPPER = 2;
var previousSortColumn ;
var order;
/* The original build store you provided */
var buildStore = function(column,tbl){
var store = [];
for (var rowpos = 1, len = tbl.rows.length; rowpos < len; rowpos++) { // skip row #1 as it is the header
var row = tbl.rows[rowpos];
var i_textContent = row.cells[column].textContent;
while (i_textContent.indexOf(' ') != -1) { // remove spaces
i_textContent = i_textContent.replace(' ', '');
}
var sortnr = i_textContent;
var type = row.getAttribute('type');
var level = row.getAttribute('level');
var depth = row.getAttribute('depth');
store.push({sortnr: sortnr, row: row, storelength: store.length, type: type, level: level, depth: depth});
}
return store;
}
// the order convention you offered
var triggerOrder = function(){
if (order==ASC){
order = DESC;
} else if (order==DESC || !order){
order = ASC;
}
}
// the code you provided
var getLevel = function(obj){
if (obj && obj.lastIndexOf('-') > 0) {
return obj.substring(0, obj.lastIndexOf('-'));
}
return obj;
}
function sortRoot(a,b){
var aSort = a[SORTNR_INDEX], bSort = b[SORTNR_INDEX];
return compareWithOrder(aSort,bSort);
};
var sortSubs = function(x,y){
var xtype = x['type'];
var ytype = y['type'];
if (xtype == 'root'){
return -1;
} else if (xtype == ytype) {
var xSort = x['sortnr'];
var ySort = y['sortnr'];
return compareWithOrder(xSort,ySort);
}
}
var compareWithOrder = function(x,y){
if (isNaN(parseInt(x))) {
return order * x.localeCompare(y);
} else {
x = parseInt(x);
y = parseInt(y);
if (x < y) {
return -1 * order;
} else if (x > y) {
return 1 * order;
} else {
return 0;
}
}
};
//assumes they are aligned by depth (i.e. will always have a root then subs). if not, an additional sort can be made beforehand
function getGroupsByLevel(store){
var group = [];
var groupIndex=0;
var lower =0, upper, sortNo;
if (store.length > 0) {
var x,y;
for (var i = 0; i < store.length; i++) {
x = store[i];
if (store[i+1]){
y = store[i+1]
} else{
y = {};
}
var xtype = x['type'];
var ytype = y['type'];
if (xtype=='root'){
sortNo = x['sortnr'];
}
var xlevel = getLevel(x['level']);
var ylevel = getLevel(y['level']);
if (xlevel != ylevel){
group[groupIndex] = [sortNo,lower,i];
lower=i+1;
groupIndex++;
}
}
}
return group;
};
function sortTable(column, thisrow) {
order = thisrow.getAttribute('order');
triggerOrder();
thisrow.setAttribute('order',order);
var tbl = document.getElementById("table1").tBodies[0];
if (!tbl) return;
/* Build a store object that has every element in the table, we will use this to sort */
var store = buildStore(column,tbl);
var groups = getGroupsByLevel(store);
groups.sort(sortRoot);
var newStore=[];
for (var i=0;i<groups.length;i++){
var group = groups[i];
var rootAndSubs = store.slice(group[LOWER],group[UPPER]+1);
rootAndSubs.sort(sortSubs);
newStore=newStore.concat(rootAndSubs);
}
//update table
for (var i = 0; i < newStore.length; i++) {
tbl.appendChild(newStore[i]['row']);
}
store = null;
order = null;
}
Basically it goes like this:
set +trigger the order
build the store just like you intended
get groups of roots and their subs
sort the groups and then sort the each of the subs for the group
update the view
This is the first approach i thought of.