This part is pretty basic but it is really important that you master this if you want to do cross browser DHTML in the future. The DOM specification is available at http://www.w3.org/dom/.

Catching the event

This part is still not finished in the W3C DOM and it is just at an early stage of DOM level 2 so here I'll have to do some browser detection. I've added an onclick attribute to the table and this passes an argument called event. In the IE case this is an object that is a property of the window object but since the window object is always in scope (like a global with statement) I don't need to write window.event and in Netscape this is created as the event occurs (I don't know were it belongs but I think it is a property of the target element. Correct me if I'm wrong). The TABLE tag looks like this:

<table onclick="sortColumn(event)">
<thead>
   <tr>...</tr>
   ...
</thead>
<tbody>
   <tr>...</tr>
   ...
</tbody>
</table>

The function sortColumn takes the target element of the event object and traverses up the tree to see if the heading was clicked. The next step is to see if the custom attribute _descending is set. If it is set invert it or else set it to true. You also want to find out which index the current column is and since the DOM doesn't have a special method for this you loop through all childNodes of the parentNode and test if it is the same node as the current.

Next you traverse the tree upwards until you find the actual TABLE tag. These traversing upwards is one of my most used functions and it looks like this. (In this case I've made it less general)

function getParent(el, pTagName) {
   if (el == null) return null;   //passed the root node
   else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
      // The nodeType == 1 is a test if the node is an actual element
      // Gecko has a bug that gives HTML tagNames in lowercase
      return el;
   else
      return getParent(el.parentNode, pTagName);   // traverse up
}

Now you have all that you need to call the sortTable function.

Getting the contents

The first argument of the sortTable function is the table node and with this you get the first TBODY element with tableNode.tBodies[0]. Since the sort method only works with the Array object you have to copy all the table rows from the TBODY to an array. After you've sorted the array you need to insert the table rows again. This is made by looping through the array of TRs and inserting last of the table body. Since the array only contains references to the TRs of the actual table these are removed before they are inserted. The entire function for all this is shown below.

function sortTable(tableNode, nCol, bDesc, sType) {
   var tBody = tableNode.tBodies[0];
   var trs = tBody.childNodes;
   var a = new Array();
   
   for (var i=0; i<trs.length; i++) {
      a[i] = trs[i];
   }
   
   a.sort(compareByColumn(nCol, bDesc, sType));
   
   for (var i=0; i<a.length; i++) {
      tBody.appendChild(a[i]);
   }
}

The arrows

The arrows are two SPAN nodes that are created at initiation and inserted into the TDs at need. This shows some very basics of how the standard DOM is use so I'll show you the code for this as well.

var arrowUp = document.createElement("SPAN");
var tn = document.createTextNode("5");
// Since I'm using the webdings font this will give a nice arrow
arrowUp.appendChild(tn);
arrowUp.setAttribute("class","arrow");

Using the table sorting in your own tables

Next I'll show you a demo table that uses this and I'll also tell you what you need to use this in your pages.




Defining the sort
Manipulating the DOM tree
Demo and instructions how to use it in your pages
Sorting with behaviors

Author: Erik Arvidsson