Link to home
Start Free TrialLog in
Avatar of mildurait
milduraitFlag for Australia

asked on

Javascript to sort html table based on values in a column

Here's a small challenge for a Javascript Guru.
I would like function to dynamically reorder <tr> nodes in a <tbody> container detailed as below.

function reOrder(tb,ci1,ci2,ci3){
  ...experts code here
  }

parameters
tb : <tbody> node
ci1 : column index (1-based) Primary Sort Colum (If zero, don't sort)
ci2 : column index (1-based) Secondary Sort Column (If zero, don't sort)
ci3 : column index (1-based) Tertiary Sort Column (If zero, don't sort)
ord: 1=ascending sort, 2=descending sort

My table would be formatted like:
<table>
     <tr>
          <td onclick=""reOrder(myTBody,1,0,0);">ID</td>
          <td onclick=""reOrder(myTBody,2,3,1);">Name</td>
          <td onclick=""reOrder(myTBody,3,2,1);">DOB</td></tr>"
     </tr>
     <tbody id="myTBody">
         <tr>
            <td sortvalue="0000001">1</td>
            <td sortvalue="Peter">Peter</td>
            <td sortvalue="19750119">19/01/1975</td>
          </tr>
           <tr>
              <td sortvalue="0000002">2</td>
              <td sortvalue="Mark">Mark</td>
              <td sortvalue="19880731">31/07/1988</td>
           </tr>
            <tr>
                <td sortvalue="0000003">3</td>
                <td sortvalue="Jane">Jane</td>
                <td sortvalue="19600201">01/02/1960</td>
            </tr>
     </tbody>
</table>

Please note, I would like to sort on the sortvalue property of each td node rather than the value displayed.
Avatar of HonorGod
HonorGod
Flag of United States of America image


Title: custom javascript sorting using generic function
 URL: http://www.codeproject.com/useritems/custom_javascript_sorting.asp
Avatar of mildurait

ASKER

Thanks HonorGod

Are you able to translate into the format in my question?
function reOrder(tb,ci1,ci2,ci3){
  ...experts code here
  }

I have been trying... it is quite challenging... :-)
okey try this
<table>
     <tr>
          <td onclick="reOrder('myTBody',1,0,0);">ID</td>
          <td onclick="reOrder('myTBody',2,3,1);">Name</td>
          <td onclick="reOrder('myTBody',3,2,1);">DOB</td></tr>
     </tr>
     <tbody id="myTBody">
         <tr ordernum=1>
            <td sortvalue="0000001">1</td>
            <td sortvalue="Peter">Peter</td>
            <td sortvalue="19750119">19/01/1975</td>
          </tr>
           <tr ordernum=2>
              <td sortvalue="0000002">2</td>
              <td sortvalue="Mark">Mark</td>
              <td sortvalue="19880731">31/07/1988</td>
           </tr>
            <tr ordernum=3>
                <td sortvalue="0000003">3</td>
                <td sortvalue="Jane">Jane</td>
                <td sortvalue="19600201">01/02/1960</td>
            </tr>
     </tbody>
</table>
 
<script type="text/javascript">
var trTagsArray = new Array();
function initTBody(){
  var tbodytag = document.getElementById("myTBody");
  var tbodytagChilds = tbodytag.childNodes
  var i = 0;
  for (i=0;i<tbodytagChilds.length;i++){
    if (tbodytagChilds[i].nodeName == "TR"){
      trTagsArray.push(tbodytagChilds[i]);
    }
  }
 
}
function reOrder(tbodyid,o1,o2,o3){
  var tbodytag = document.getElementById(tbodyid);
  var tbodytagChilds = tbodytag.childNodes
  var i = 0;
  
  while (tbodytagChilds.length > 0){
    tbodytag.removeChild(tbodytagChilds[0]);
  }
  
  for (i=0;i<trTagsArray.length;i++){
    if (trTagsArray[i].attributes['ordernum'].value == o1){
      tbodytag.appendChild(trTagsArray[i]);
    }
  }
  for (i=0;i<trTagsArray.length;i++){
    if (trTagsArray[i].attributes['ordernum'].value == o2){
      tbodytag.appendChild(trTagsArray[i]);
    }
  }
  for (i=0;i<trTagsArray.length;i++){
    if (trTagsArray[i].attributes['ordernum'].value == o3){
      tbodytag.appendChild(trTagsArray[i]);
    }
  }
}
 
initTBody();
</script>

Open in new window

<Here's a small challenge for a Javascript Guru.>
I thought so ;-)
Do you think it's possible?
@fsze88

Great start: looks like you are headed in the right direction, however this is the outcome i am getting.

<ID Sort> - Missing records 2 and 3
ID Name DOB
1 Peter 19/01/1975

<Name Sort>  Should be Jane, Mark, Peter
ID Name DOB
2 Mark 31/07/1988
3 Jane 01/02/1960
1 Peter 19/01/1975

<DOB Clicked> Should be 01/02/1960, 31/07/1988, 19/01/1975
ID Name DOB
3 Jane 01/02/1960
2 Mark 31/07/1988
1 Peter 19/01/1975

mildurait,
1)
I sorted the order by
          <td onclick="reOrder('myTBody',1,0,0);">ID</td>
          <td onclick="reOrder('myTBody',2,3,1);">Name</td>
          <td onclick="reOrder('myTBody',3,2,1);">DOB</td></tr>
ID: 1,0,0, Name : 2,3,1, DOB: 3,2,1
that's not what you are looking for?
2)
you want sorted by td attributes?
            <td sortvalue="0000001">1</td>
            <td sortvalue="Peter">Peter</td>
            <td sortvalue="19750119">19/01/1975</td>
if yes (case 2), what is ID: 1,0,0, Name : 2,3,1, DOB: 3,2,1 stand for?
THANKS!
Id like my function to sort by values held in the sortvalue attribute of the <td>
eg
<td sortvalue="0000001">1</td>                         Sort on 0000001
<td sortvalue="Peter">Peter</td>                        Sort on Peter      
<td sortvalue="19750119">19/01/1975</td>      Sort on 19750119

ci1, ci2, ci1
In this case
reOrder(myTBody,1,0,0) should sort by column 1 (ID)
reOrder(myTBody,2,3,1) should sort by column 2 (Name) then Column 3 (DOB) then column (1) ID
reOrder(myTBody,3,2,1) should sort by column 3 (DOB) then Column 2 (Name) then column (1) ID
If you add another few records to the table, you will be able to test your secondary and tertiary sorts

            <tr>
              <td sortvalue="0000004">4</td>
              <td sortvalue="Mark">Mark</td>
              <td sortvalue="19711212">12/12/1971</td>
           </tr>
           <tr>
              <td sortvalue="0000005">5</td>
              <td sortvalue="Andrew">Andrew</td>
              <td sortvalue="19711212>12/12/1971</td>
           </tr>
          <tr>
              <td sortvalue="0000006">6</td>
              <td sortvalue="Andrew">Andrew</td>
              <td sortvalue="19711212>12/12/1971</td>
           </tr>

@HonorGod
How is your brew coming along?
@fsze88
Do you have a clearer understanding of what I'm chasing?
yes, I understood!
this is approaching your answer....
Please, try it first and let me know any enchancement.
Note : I may goto lunch, but I will back soon..
<table>
     <tr>
          <td onclick="reOrder('myTBody',1,0,0);">ID</td>
          <td onclick="reOrder('myTBody',2,3,1);">Name</td>
          <td onclick="reOrder('myTBody',3,2,1);">DOB</td></tr>
     </tr>
     <tbody id="myTBody">
         <tr ordernum=1>
            <td sortvalue="0000001">1</td>
            <td sortvalue="Peter">Peter</td>
            <td sortvalue="19750119">19/01/1975</td>
          </tr>
           <tr ordernum=2>
              <td sortvalue="0000002">2</td>
              <td sortvalue="Mark">Mark</td>
              <td sortvalue="19880731">31/07/1988</td>
           </tr>
            <tr ordernum=3>
                <td sortvalue="0000003">3</td>
                <td sortvalue="Jane">Jane</td>
                <td sortvalue="19600201">01/02/1960</td>
            </tr>
     </tbody>
</table>
 
<script type="text/javascript">
var trTagsArray = new Array();
 
function initTBody(){
  var tbodytag = document.getElementById("myTBody");
  var tbodytagChilds = tbodytag.childNodes
  var i = 0;
  for (i=0;i<tbodytagChilds.length;i++){
    if (tbodytagChilds[i].nodeName == "TR"){
      trTagsArray.push(tbodytagChilds[i]);
    }
  }
}
 
 
function reOrder(tbodyid,o1,o2,o3){
  var tbodytag = document.getElementById(tbodyid);
  var tbodytagChilds = tbodytag.childNodes
  var i = 0;
  var smallestSortValue = "ZZZZZZZZZZ";
  var smallestIndex;
  var tempArray = new Array().concat(trTagsArray);
  
  while (tbodytagChilds.length > 0){
    tbodytag.removeChild(tbodytagChilds[0]);
  }
  
  while (tempArray.length > 0){
    smallestSortValue = "ZZZZZZZZZZ";
    for (i=0;i<tempArray.length;i++){
      if (getSortValue(tempArray[i],o1) < smallestSortValue){
        smallestSortValue = getSortValue(tempArray[i],o1);
        smallestIndex = i;
      }
    }
    tbodytag.appendChild(tempArray[smallestIndex]);
    tempArray.splice(smallestIndex,1);
    
  }  
 
}
 
function getSortValue(trTag,tagIndex){
  var trTagChilds = trTag.childNodes;
  var indexedTdTag;
  var numTdTag = 0;
  var j=0;
  for (j=0;j<trTagChilds.length;j++){
    if (trTagChilds[j].nodeName == "TD"){
      ++numTdTag;
      if (tagIndex == numTdTag){
        indexedTdTag = trTagChilds[j];
        break;
      }
    }
  }
  return indexedTdTag.attributes['sortvalue'].value;
}
 
initTBody();
</script>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Kin Fat SZE
Kin Fat SZE
Flag of Hong Kong image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
@fsze88
I must say brilliant work my friend.
Just when I am working with a recordset of say 1000 rows, it's a bit tardy and invokes script cancellation dialog in IE.
Any suggestions to make it work faster?
Works brilliantly for tables of 100 rows.
With a small tweek to the initBody function I was able to get the code to work with multiple tbody containers on the one page.
Thanks, I could not have done this by myself!
try this, this should be a bit faster.. But a bit....
it is bubble sort technology... If you still want it to be faster, try another methods (insertion sort,Quicksort,Comb sort,Cocktail sort .....)
http://en.wikipedia.org/wiki/Bubble_sort
Thanks for your appreciate
<table>
     <tr>
          <td onclick="reOrder('myTBody',1,0,0);">ID</td>
          <td onclick="reOrder('myTBody',2,3,1);">Name</td>
          <td onclick="reOrder('myTBody',3,2,1);">DOB</td></tr>
     </tr>
     <tbody id="myTBody">
         <tr ordernum=1>
            <td sortvalue="0000001">1</td>
            <td sortvalue="Peter">Peter</td>
            <td sortvalue="19750119">19/01/1975</td>
          </tr>
            <tr ordernum=3>
                <td sortvalue="0000004">4</td>
                <td sortvalue="Jane">Jane</td>
                <td sortvalue="19760201">01/02/1976</td>
            </tr>
           <tr ordernum=2>
              <td sortvalue="0000002">2</td>
              <td sortvalue="Mark">Mark</td>
              <td sortvalue="19880731">31/07/1988</td>
           </tr>
            <tr ordernum=3>
                <td sortvalue="0000003">3</td>
                <td sortvalue="Jane">Jane</td>
                <td sortvalue="19600201">01/02/1960</td>
            </tr>
     </tbody>
</table>
 
<script type="text/javascript">
var trTagsArray = new Array();
 
function initTBody(){
  var tbodytag = document.getElementById("myTBody");
  var tbodytagChilds = tbodytag.childNodes
  var i = 0;
  for (i=0;i<tbodytagChilds.length;i++){
    if (tbodytagChilds[i].nodeName == "TR"){
      trTagsArray.push(tbodytagChilds[i]);
    }
  }
}
 
 
function reOrder(tbodyid,o1,o2,o3){
  var tbodytag = document.getElementById(tbodyid);
  var tbodytagChilds = tbodytag.childNodes;
  var splicedTrTag;
  var oValue;
  var i = 0;
  var smallestSortValue = "ZZZZZZZZZZ";
  var smallestIndex;
  var tempArray = new Array().concat(trTagsArray);
  var tempArray2 = new Array();
  var sortValue="";
  while (tbodytagChilds.length > 0){
    tbodytag.removeChild(tbodytagChilds[0]);
  }
 
 
 
  for (var k=3;k>=1;k--){
    oValue = eval("o" + k);
    while (tempArray.length > 0){
      smallestSortValue = "ZZZZZZZZZZ";
      for (i=0;i<tempArray.length;i++){
        sortValue = getSortValue(tempArray[i],oValue);
        if (sortValue < smallestSortValue){
          smallestSortValue = sortValue;
          smallestIndex = i;
        }
      }
//      tbodytag.appendChild(tempArray[smallestIndex]);
      splicedTrTag = tempArray[smallestIndex];
      tbodytag.appendChild(splicedTrTag);
      tempArray.splice(smallestIndex,1);
      tempArray2.push(splicedTrTag);
    }  
    
    tempArray = new Array().concat(tempArray2);
    tempArray2 = new Array();
  }
 
}
 
function getSortValue(trTag,tagIndex){
  var trTagChilds = trTag.childNodes;
  var indexedTdTag;
  var numTdTag = 0;
  var j=0;
  var returnValue = "";
  for (j=0;j<trTagChilds.length;j++){
    if (trTagChilds[j].nodeName == "TD"){
      ++numTdTag;
      if (tagIndex == numTdTag){
        indexedTdTag = trTagChilds[j];
        break;
      }
    }
  }
  
  try{
    returnValue = indexedTdTag.attributes['sortvalue'].value;
  }catch(err){
    returnValue = "";
  }
  
  return returnValue;
}
 
initTBody();
</script>

Open in new window

Nicely done.
@HonorGod.
Yeah... pretty cool hey.
Heh just wanted to say appreciate you putting Jesus out there mate - well done!
@fsze88
I am going to open up another question, asking for quicksort method of sorting the array.
Might be another easy 500 points for you.