-->
Bookmark and Share

Table Sort

See the demo page for the finished version of the code.

Choosing a Sort Algorithm

There are several well-known methods for sorting items in a list. Some are theoretically faster than others but there are other considerations, such as the number of items to sort and the expense of moving items around within the list.

For an HTML table, we can assume a fairly small number of rows. Since web pages are documents intended for human viewing, displaying millions, thousands or even hundreds of rows of data is generally not practical. Likewise, since we will be dynamically modifying the DOM, we want to minimize the number of row swaps performed since these can be relatively expensive operations.

The selection sort makes a good candidate. Compared to other sort algorithms, it's relatively fast for the number of items we'd expect to find in a typical table display. Also, in a worst case senario, it requires only one swap per item.

The Selection Sort

A selection sort works like this: starting with the entire list of items, you find the smallest one. You then move this item to the beginning of the list. Then you look at the items that are left, again finding the one with the smallest value. That item you move to the position just after the first.

This continues until you get down to the last item left which, by then, will be the largest in the list. The diagram below illustrates the process.

Step 1
7
5
3
1
4
 
1
7
5
3
4
Step 2
1
7
5
3
4
 
1
3
7
5
4
Step 3
1
3
7
5
4
 
1
3
4
7
5
Step 4
1
3
4
7
5
 
1
3
4
5
7

This process will work well for sorting the table rows because moving an item involves two actions, removing it (the row node) from the list (table section node) and then inserting it back at a specific location. The DOM already provides simple methods for removing and inserting nodes.

The Sort Code

So let's look at the sortTable() function. The first order of business is to get the table or table section that contains the rows to be sorted.

function sortTable(col) {

  // Get the table section to sort.
  var tblEl = document.getElementById("planetData");

  // Set the table display style to "none" - necessary for Netscape 6 
  // browsers.
  var oldDsply = tblEl.style.display;
  tblEl.style.display = "none";

Here, we just use document.getElementByID() with the id of the TBODY tag, "planetData."

Browser Compatibility

Netscape 6 has a nasty habit of misrendering a table when you move rows around. To prevent this, we have to first set its display style property to none and then restore it after we're done sorting. Fortunately, this has no adverse effect on other browsers so it's done for all.

Next we do the actual sorting. We start with a loop to run from the first row to the next to last row. This will give us the insert position for each step. Within this loop, we want to look at all the rows between this position and the last row to find the one with the smallest value in the selected column. So a second, inner loop is started.

  // Sort the rows based on the content of the specified column
  // using a selection sort.

  var tmpEl;
  var i, j;
  var minVal, minIdx;
  var testVal;
  var cmp;

  for (i = 0; i < tblEl.rows.length - 1; i++) {

    // Assume the current row has the minimum value.
    minIdx = i;
    minVal = getTextValue(tblEl.rows[i].cells[col]);

    // Search the rows that follow the current one for a smaller value.
    for (j = i + 1; j < tblEl.rows.length; j++) {
      testVal = getTextValue(tblEl.rows[j].cells[col]);
      cmp = compareValues(minVal, testVal);
      // If this row has a smaller value than the current minimum,
      // remember its position and update the current minimum value.
      if (cmp > 0) {
        minIdx = j;
        minVal = testVal;
      }
    }

The minVal variable contains the smallest column value found so far while minIdx is used to keep track of the index of the row that value was found in. We initially assume the first row has the smallest value, but any of the rows could be used since all of them will be compared.

Once we finish this inner loop, we'll know which row needs to be moved to the current insert position. If it happens to be the row currently in that position, we just leave it. Otherwise, we move it.

    // By now, we have the row with the smallest value. Remove it from
    // the table and insert it before the current row.
    if (minIdx > i) {
      tmpEl = tblEl.removeChild(tblEl.rows[minIdx]);
      tblEl.insertBefore(tmpEl, tblEl.rows[i]);
    }
  }

The DOM removeChild() method removes the row from the document and returns that element node. The row is still a valid element node, it's just no longer a part of the document. We can then use the DOM insertBefore() method to move the row node back into the table section at the current insert position.

Once the rows have been sorted, we can restore the table display and return.

  // Restore the table's display style.
  tblEl.style.display = oldDsply;

  return false;
}

Note that the sort function returns a value of false because it will be called using the onclick event of a link tag. We don't want the browser to actually follow the link, just want it to call the sort function. Returning false will prevent the browser from trying to load the link URL.

Now let's see the code in action.