Sakthivel
Sakthivel

Reputation: 666

How to order the table rows based on its value in javascript

Am working on the table, my aim is to display rows orderly based on its sum of columns. I mean, highest valued rows should be displayed first and then, second highest values, then, go on.. Have tried and could not make it. Just give me an idea, and that is good enough for me. Am not able to come to any idea on how to reshuffle the rows based on its sum values. Any idea on this?

<div id="na_1" style="border: 1px solid gray;width: 450px;padding:10px;">
<form>
<input type="radio" value="All" onclick="Turnthis();"/>All
<input type="radio" value="Top15" onclick="TurnOutthis();"/>Top5
</form>
<table id="bt_01" border="1" width="100%">
<thead>
<tr><td>head1</td><td>head2</td><td>head3</td><td>head4</td><td>head5</td><td>head6</td><td>head7</td></tr>
</thead>
<tbody>
<tr><td>Subject1</td><td>501</td><td>501</td><td>501</td><td>550</td><td>560</td><td>570</td></tr>
<tr><td>Subject2</td><td>620</td><td>640</td><td>605</td><td>650</td><td>600</td><td>604</td></tr>
<tr><td>Subject3</td><td>730</td><td>730</td><td>740</td><td>750</td><td>760</td><td>790</td></tr>
<tr><td>Subject4</td><td>700</td><td>701</td><td>700</td><td>702</td><td>700</td><td>703</td></tr>
<tr><td>Subject5</td><td>220</td><td>201</td><td>202</td><td>222</td><td>210</td><td>203</td></tr>
<tr><td>Subject6</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
<tr><td>Subject7</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
<tr><td>Subject8</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
<tr><td>Total</td><td>202</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
</tbody>  
</table>

</div>

After I pressed the 'Top5' button, then, the table should be displayed as follows[sample]

    <div id="na_1" style="border: 1px solid gray;width: 450px;padding:10px;">
    <form>
    <input type="radio" value="All" onclick="Turnthis();"/>All
    <input type="radio" value="Top15" onclick="TurnOutthis();"/>Top5
    </form>
    <table id="bt_01" border="1" width="100%">
    <thead>
    <tr><td>head1</td><td>head2</td><td>head3</td><td>head4</td><td>head5</td><td>head6</td><td>head7</td></tr>
    </thead>
    <tbody>
<tr><td>Subject3</td><td>730</td><td>730</td><td>740</td><td>750</td><td>760</td><td>790</td></tr>
    <tr><td>Subject4</td><td>700</td><td>701</td><td>700</td><td>702</td><td>700</td><td>703</td></tr>
<tr><td>Subject2</td><td>620</td><td>640</td><td>605</td><td>650</td><td>600</td><td>604</td></tr>
    <tr><td>Subject1</td><td>501</td><td>501</td><td>501</td><td>550</td><td>560</td><td>570</td></tr>
<tr><td>Subject5</td><td>220</td><td>201</td><td>202</td><td>222</td><td>210</td><td>203</td></tr>
 </tbody>  
    </table></div>

Hope this makes sense. For your kind information, i except code only in javascript not in jquery.

Upvotes: 0

Views: 94

Answers (3)

AL-zami
AL-zami

Reputation: 9076

I assume you want the "total" row at the end of the table after sort.Otherwise code can be 10-12 lines shorter.

i come up with this solution.I've commented out every portion for convenience .With a little help form getElementsByTagName,removeChild,createElement,and appendChild methods you can achieve what you are trying to do.It is really simple.I advice you go through it.The main thing is create an array of objects which hold three properties.And the properties are the actual tr element,its sum and the first td element which holds subject1,2,3....and Total string.Then sort them down with Array.prototype.sort() then add them serially to your tbody element

var radio=document.getElementById('radio');
if(radio.checked == true){   //check for radio element is checked or not
   radio.checked=false;
}
var table=document.getElementById('bt_01');
var serialTdArr=[]; //array which will hold the array of objects
var storageForTotal='';// store the tr element that has 'Total' as value of its first td element
function Turnthis(e){

   var tbody=document.getElementsByTagName('tbody')[0]; //get the current tbody element

    var tr=tbody.getElementsByTagName('tr'); //get all tr elements inside tbody
	
	for(i=0;i<tr.length;i++){  // loop over the tr elements
	    var sum=0;
	    var td=tr[i].getElementsByTagName('td');  //get all td element inside every tr element
		for(j=1;j<td.length;j++){
		   
			
			sum+=parseInt(td[j].innerHTML);  // sum them up
			
		   
		}
		var firstTd=td[0].innerHTML;  //save every subject1,subject2,3,...and Total string to a seperate variable
		
		serialTdArr.push({index:tr[i],sum:sum,pointer:firstTd});  // an object which holds the tr element,its sum and its first td element value is pushed inside serialTdArr
		
		
	}
	
	
	var sortedArr=serialTdArr.sort(function(a,b){  // sort them down from higher to lower
	     
		if(a.sum < b.sum){
		   return 1;
		}
		if(a.sum > b.sum){
		   return -1;
		}
		return 0;
	   
	});
	
	
	     
		table.removeChild(tbody);  // remove the current tbody
		var newTbody=document.createElement('tbody'); // create a new tbody
		table.appendChild(newTbody); // append it to table
		
	for(i=0;i<sortedArr.length;i++){
	  if((sortedArr[i].pointer) != 'Total'){  // if it has no  "Total" string then add them to tbody
	    
	
	   newTbody.appendChild(sortedArr[i].index); // add to tbody
	}else{
	  
	   storageForTotal=sortedArr[i].index;  // 'Total' row will be seperated and stored in a variable to be added later at the end of the table
	
	}
	
	}
	newTbody.appendChild(storageForTotal);  // add the tr which 'Total' to the last of td element
	
	
}
<div id="na_1" style="border: 1px solid gray;width: 450px;padding:10px;">
<form>
<input type="radio" id='radio' value="Sort Them All" onchange="Turnthis();"/>Sort Them All

</form>
<table id="bt_01" border="1" width="100%">
<thead>
<tr><td>head1</td><td>head2</td><td>head3</td><td>head4</td><td>head5</td><td>head6</td><td>head7</td></tr>
</thead>
<tbody>
<tr><td>Subject1</td><td>501</td><td>501</td><td>501</td><td>550</td><td>560</td><td>570</td></tr>
<tr><td>Subject2</td><td>620</td><td>640</td><td>605</td><td>650</td><td>600</td><td>604</td></tr>
<tr><td>Subject3</td><td>730</td><td>730</td><td>740</td><td>750</td><td>760</td><td>790</td></tr>
<tr><td>Subject4</td><td>700</td><td>701</td><td>700</td><td>702</td><td>700</td><td>703</td></tr>
<tr><td>Subject5</td><td>220</td><td>201</td><td>202</td><td>222</td><td>210</td><td>203</td></tr>
<tr><td>Subject6</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
<tr><td>Subject7</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
<tr><td>Subject8</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
<tr><td>Total</td><td>202</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
</tbody>  

Upvotes: 0

RobG
RobG

Reputation: 147453

The trick is to get the rows you want and put them into an array, then sort the array and put the rows into the table in the right order. The following will sort the rows based on the cell values, so if the first cell value is equal, it uses the second, and so on. The sort may not be stable since it just uses the built–in Array.prototype.sort. If you want to to be stable, that is pretty simple (but generally not required).

Firstly, get the relevant tBody element and rows:

var tBody = document.getElementById('bt_01').tBodies[0];
var rows = tBody.rows;

rows is a live collection so you want to build an array form it (also helps with sorting). The following works fine in modern browsers:

var rowArr = Array.prototype.slice.call(rows);

But will not work in IE 8 and lower, you'll need to use a for loop (just one extra line of code):

var rowArr = [];
for (var i=0, iLen=rows.length; i<iLen; i++) rowArr[i] = rows[i];

To keep the last row as the last, just keep a reference:

var lastRow = rowArr[rowArr.length - 1];

Now sort based on the cell values from the second cell onward:

rowArr.sort(function(a, b) {
  var aVal, bVal;
  for (var i = 1, iLen = a.cells.length; i<iLen; i++) {
    aVal = a.cells[i].textContent || a.cells[i].innerText;
    bVal = b.cells[i].textContent || b.cells[i].innerText;
    if (aVal != bVal) return aVal - bVal;
  }
  return 0;
});

Now put the rows into order:

for (var j=0, jLen=rowArr.length; j<jLen; j++) {
  tBody.appendChild(rowArr[j]);
}

and finally, put the bottom row back at the bottom:

tBody.appendChild(lastRow);

and you're done. And it's shorter than the offered jQuery alternative (and likely a lot faster). ;-)

It would be best to put footer row in separate tFoot section as you've done with the header.

Edit

If you want to sort based on the sum of the values in each row, the sort part becomes:

rowArr.sort(function(a, b) {
  var aSum = 0, bSum = 0;
  for (var i = 1, iLen = a.cells.length; i<iLen; i++) {
    aSum += parseFloat(a.cells[i].textContent || a.cells[i].innerText);
    bSum += parseFloat(b.cells[i].textContent || b.cells[i].innerText);
  }
  return aSum - bSum;
});

Upvotes: 1

Kokizzu
Kokizzu

Reputation: 26888

This code works and tested on Chrome 30

Non-jQuery version (updated question):

<html>
<body>
  <div id="na_1" style="border: 1px solid gray;width: 450px;padding:10px;">
    <table id="bt_01" border="1" width="100%">
      <thead>
        <tr><td>head1</td><td>head2</td><td>head3</td><td>head4</td><td>head5</td><td>head6</td><td>head7</td></tr>
      </thead>
      <tbody>
        <tr><td>Subject1</td><td>501</td><td>501</td><td>501</td><td>550</td><td>560</td><td>570</td></tr>
        <tr><td>Subject2</td><td>620</td><td>640</td><td>605</td><td>650</td><td>600</td><td>604</td></tr>
        <tr><td>Subject3</td><td>730</td><td>730</td><td>740</td><td>750</td><td>760</td><td>790</td></tr>
        <tr><td>Subject4</td><td>700</td><td>701</td><td>700</td><td>702</td><td>700</td><td>703</td></tr>
        <tr><td>Subject5</td><td>220</td><td>201</td><td>202</td><td>222</td><td>210</td><td>203</td></tr>
        <tr><td>Subject6</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
        <tr><td>Subject7</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
        <tr><td>Subject8</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
      </tbody>
      <tfoot>
        <tr><td>Total</td><td>202</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
      </tfoot>
    </table>
  </div>
  <input type='button' onclick='sort()' value='sort by sum' />
  <script>
    function sort() {
      var t = document.getElementById('bt_01').children[1]; // tbody
      var arr = [];
        // find all tr
      var trs = t.children;
      for(;trs.length;) {
        var tr = trs[0];
        // find all td and calculate the sum
        var sum = 0;
        var tds = tr.children;
        for(var y in tds) {
          var td = tds[y];
          var v = +td.textContent;
          if (!isNaN(v)) sum += v;
        };
        // move them to arr
        tr = tr.parentNode.removeChild(tr)
        arr.push({sum: sum,tr: tr});
      };
      // sort it
      arr.sort(function(a, b) {
        if (a.sum < b.sum) return 1;
        if (a.sum > b.sum) return -1;
        return 0;
      });
      // attach back the tr in order
      for (var z in arr) t.appendChild(arr[z].tr)
    }
  </script>
</body>    
</html>

jQuery version:

<html>
<body>
  <script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
  <div id="na_1" style="border: 1px solid gray;width: 450px;padding:10px;">
    <table id="bt_01" border="1" width="100%">
      <thead>
        <tr><td>head1</td><td>head2</td><td>head3</td><td>head4</td><td>head5</td><td>head6</td><td>head7</td></tr>
      </thead>
      <tbody>
        <tr><td>Subject1</td><td>501</td><td>501</td><td>501</td><td>550</td><td>560</td><td>570</td></tr>
        <tr><td>Subject2</td><td>620</td><td>640</td><td>605</td><td>650</td><td>600</td><td>604</td></tr>
        <tr><td>Subject3</td><td>730</td><td>730</td><td>740</td><td>750</td><td>760</td><td>790</td></tr>
        <tr><td>Subject4</td><td>700</td><td>701</td><td>700</td><td>702</td><td>700</td><td>703</td></tr>
        <tr><td>Subject5</td><td>220</td><td>201</td><td>202</td><td>222</td><td>210</td><td>203</td></tr>
        <tr><td>Subject6</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
        <tr><td>Subject7</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
        <tr><td>Subject8</td><td>200</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
      </tbody>
      <tfoot>
        <tr><td>Total</td><td>202</td><td>201</td><td>200</td><td>202</td><td>200</td><td>203</td></tr>
      </tfoot>
    </table>
  </div>
  <input type='button' onclick='sort()' value='sort by sum' />
  <script>
    function sort() {
      var t = $('#bt_01').find('tbody');
      var arr = [];
        // find all tr
      t.find('tr').each(function(idx, tr) {
        tr = $(tr);
        // find all td and calculate the sum
        var sum = 0;
        tr.find('td').each(function(idx, td) {
          td = $(td);
          var v = +td.text();
          if (!isNaN(v)) sum += v;
        });
        // move them to arr
        arr.push({sum: sum,tr: tr.detach()});
      });
      // sort it
      arr.sort(function(a, b) {
        if (a.sum < b.sum) return 1;
        if (a.sum > b.sum) return -1;
        return 0;
      });
      // attach back the tr in order
      for (var z in arr) t.append(arr[z].tr)
    }
  </script>
</body>    
</html>

Upvotes: 0

Related Questions