WebToolkit

Sortable HTML table

Overview  

This JavaScript code can be used to convert tables in ordinary HTML into sortable ones. This script is unobtrusive. No additional coding is necessary. All you need to do is put header (sorting) row in THEAD section, table body rows in TBODY section, footer rows (if you need them) in TFOOT section and give your table an ID field, include the webtoolkit.sortabletable.js file and create SortableTable() object after each table.

Tested in IE5.0+, OP8.0+, FF1.0+

Sortable HTML table demo page
View the demo page for this article

Source code for index.html   (Download source code)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <title>Scrollable HTML table</title>
    <meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
    <script type="text/javascript" src="webtoolkit.sortabletable.js"></script>

    <style>
        table {
            text-align: left;
            font-size: 12px;
            font-family: verdana;
            background: #c0c0c0;
        }

        table thead  {
            cursor: pointer;
        }

        table thead tr,
        table tfoot tr {
            background: #c0c0c0;
        }

        table tbody tr {
            background: #f0f0f0;
        }

        td, th {
            border: 1px solid white;
        }
    </style>
</head>

<body>

<table cellspacing="1" cellpadding="2" class="" id="myTable" width="400">
    <thead>
        <tr>
            <th class="c1">Name</th>
            <th class="c2">Surename</th>
            <th class="c3">Age</th>
        </tr>
    </thead>

    <tbody>
        <tr class="r1">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">30</th>
        </tr>
        <tr class="r2">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">31</th>
        </tr>
        <tr class="r1">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">32</th>
        </tr>
        <tr class="r2">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">33</th>
        </tr>
        <tr class="r1">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">34</th>
        </tr>
        <tr class="r2">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">35</th>
        </tr>
        <tr class="r1">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">36</th>
        </tr>
        <tr class="r2">
            <td class="c1">John</th>
            <td class="c2">Smith</th>
            <td class="c3">37</th>
        </tr>
    </tbody>

    <tfoot>
        <tr>
            <th class="c1">Name</th>
            <th class="c2">Surename</th>
            <th class="c3">Age</th>
        </tr>
    </tfoot>
</table>

<script type="text/javascript">
var t = new SortableTable(document.getElementById('myTable'), 100);
</script>

</body>
</html>

Source code for webtoolkit.sortabletable.js   (Download source code)

/**
*
*  Sortable HTML table
*  http://www.webtoolkit.info/
*
**/

function SortableTable (tableEl) {

    this.tbody = tableEl.getElementsByTagName('tbody');
    this.thead = tableEl.getElementsByTagName('thead');
    this.tfoot = tableEl.getElementsByTagName('tfoot');

    this.getInnerText = function (el) {
        if (typeof(el.textContent) != 'undefined') return el.textContent;
        if (typeof(el.innerText) != 'undefined') return el.innerText;
        if (typeof(el.innerHTML) == 'string') return el.innerHTML.replace(/<[^<>]+>/g,'');
    }

    this.getParent = function (el, pTagName) {
        if (el == null) return null;
        else if (el.nodeType == 1 && el.tagName.toLowerCase() == pTagName.toLowerCase())
            return el;
        else
            return this.getParent(el.parentNode, pTagName);
    }

    this.sort = function (cell) {

        var column = cell.cellIndex;
        var itm = this.getInnerText(this.tbody[0].rows[1].cells[column]);
        var sortfn = this.sortCaseInsensitive;

        if (itm.match(/\d\d[-]+\d\d[-]+\d\d\d\d/)) sortfn = this.sortDate; // date format mm-dd-yyyy
        if (itm.replace(/^\s+|\s+$/g,"").match(/^[\d\.]+$/)) sortfn = this.sortNumeric;

        this.sortColumnIndex = column;

        var newRows = new Array();
        for (j = 0; j < this.tbody[0].rows.length; j++) {
            newRows[j] = this.tbody[0].rows[j];
        }

        newRows.sort(sortfn);

        if (cell.getAttribute("sortdir") == 'down') {
            newRows.reverse();
            cell.setAttribute('sortdir','up');
        } else {
            cell.setAttribute('sortdir','down');
        }

        for (i=0;i<newRows.length;i++) {
            this.tbody[0].appendChild(newRows[i]);
        }

    }

    this.sortCaseInsensitive = function(a,b) {
        aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]).toLowerCase();
        bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]).toLowerCase();
        if (aa==bb) return 0;
        if (aa<bb) return -1;
        return 1;
    }

    this.sortDate = function(a,b) {
        aa = thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]);
        bb = thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]);
        date1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
        date2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
        if (date1==date2) return 0;
        if (date1<date2) return -1;
        return 1;
    }

    this.sortNumeric = function(a,b) {
        aa = parseFloat(thisObject.getInnerText(a.cells[thisObject.sortColumnIndex]));
        if (isNaN(aa)) aa = 0;
        bb = parseFloat(thisObject.getInnerText(b.cells[thisObject.sortColumnIndex]));
        if (isNaN(bb)) bb = 0;
        return aa-bb;
    }

    // define variables
    var thisObject = this;
    var sortSection = this.thead;

    // constructor actions
    if (!(this.tbody && this.tbody[0].rows && this.tbody[0].rows.length > 0)) return;

    if (sortSection && sortSection[0].rows && sortSection[0].rows.length > 0) {
        var sortRow = sortSection[0].rows[0];
    } else {
        return;
    }

    for (var i=0; i<sortRow.cells.length; i++) {
        sortRow.cells[i].sTable = this;
        sortRow.cells[i].onclick = function () {
            this.sTable.sort(this);
            return false;
        }
    }

}