javascript - Sorting HTML table with subitems with JS -
i have 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 want sort it, first "root" "sub" items, mean root have sub a, sub b under (sorted well, under it)
i used following code works on over "sub items", cannot work doing "mix", i.e. top , 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 store object has every element in table, use sort */ for(var rowpos=1, len=tbl.rows.length; rowpos<len; rowpos++) { // skip row #1 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}); } /* sort first roots elements under */ 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; } }); /* sort elements under */ 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; < store.length; i++) { tbl.appendchild(store[i]['row']); } store = null; }
update 1: clicking once on 'columnb' not affect table (a bit of bad example on part), information sorted in correct order, click should sort in reverse order
so both roots in reverse other, root c, root b, root a, 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 problem. did reorganize code make lot more readable. of logic provided, added small bits. , btw, have duplicate id references on id="nocenter" in html.
here a working jsfiddle of solution. html 1 provided , errors , , no listener on column e. this js fiddle version has more subs on root a. can play (add data). summary of code comes after in answer.
update - taken new input data in comments , updated jsfiddle seem kept root in place, , jumped out of subset. matter of changing 1 line in sorting subs. the new fiddle.
var asc = 1; var desc = -1; var sortnr_index = 0; var lower = 1; var upper = 2; var previoussortcolumn ; var order; /* original build store provided */ var buildstore = function(column,tbl){ var store = []; (var rowpos = 1, len = tbl.rows.length; rowpos < len; rowpos++) { // skip row #1 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; } // order convention offered var triggerorder = function(){ if (order==asc){ order = desc; } else if (order==desc || !order){ order = asc; } } // code 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 aligned depth (i.e. have root subs). if not, additional sort can made beforehand function getgroupsbylevel(store){ var group = []; var groupindex=0; var lower =0, upper, sortno; if (store.length > 0) { var x,y; (var = 0; < 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 store object has every element in table, use sort */ var store = buildstore(column,tbl); var groups = getgroupsbylevel(store); groups.sort(sortroot); var newstore=[]; (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 (var = 0; < newstore.length; i++) { tbl.appendchild(newstore[i]['row']); } store = null; order = null; }
basically goes this:
- set +trigger order
- build store intended
- get groups of roots , subs
- sort groups , sort each of subs group
- update view
this first approach thought of.
Comments
Post a Comment