Reputation: 5598
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>
Upvotes: 3
Views: 607
Reputation: 6686
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.
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:
This is the first approach i thought of.
Upvotes: 3