3

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>
2
  • Can you show an example of a starting table and then of that table after it has been sorted? Commented Aug 25, 2015 at 7:36
  • @raduation see if this makes it clearer Commented Aug 25, 2015 at 8:03

1 Answer 1

3
+500

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.

Sign up to request clarification or add additional context in comments.

10 Comments

thank you for this, it works as required (btw the mistakes in my code were due to whitewashing the table data's sensitive parts)
I actually found that your solution has the same problem as mine, sub items appears to "escape" their root and are getting sorted on their own, I will post a jsFiddler of it and link
Hi, here is a populated table: jsfiddle.net/5c3Lgvsn/#&togetherjs=vgJlz3mLev sorting the table causes some sub items to "run away"
Can you highlight the change?
In that case, you can go with your own string comparison (i think you where doing localeCompare) in those cases alone. Right now it compares the actual numbers, because parseInt(0/3) is 0 and so on
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.