How to make this table sorting script treat different tables differently?

I found an in itself good table content sorting script. It can sort the contents of multiple tables and is lightweight. However, it makes the default sorting column, determined by one particular value in the script, the same for every table. While I have different tables with different characteristics, and thus with different default sorting columns.

Is it possible to make this script assign different tables different  default sorting colum numbers? This is the -- two-part -- script (see  below for what I tried; I used PHP code tags for better highlighting): 

First part, separate file:


function TSorter(){
    var table = Object;
    var trs = Array;
    var ths = Array;
    var curSortCol = Object;
    var prevSortCol = '3';
    var sortType = Object;

    function get(){}

    function getCell(index){
        return trs[index].cells[curSortCol]
    }

    /*----------------------INIT------------------------------------*/
    // Initialize the variable
    // @param tableName - the name of the table to be sorted
    /*--------------------------------------------------------------*/
    this.init = function(tableName)
    {
        table = document.getElementById(tableName);
        ths = table.getElementsByTagName("th");
        for(var i = 0; i < ths.length ; i++)
        {
            ths[i].onclick = function()
            {
                sort(this);
            }
        }
        return true;
    };

    /*----------------------SORT------------------------------------*/
    // Sorts a particular column. If it has been sorted then call reverse
    // if not, then use quicksort to get it sorted.
    // Sets the arrow direction in the headers.
    // @param oTH - the table header cell (<th>) object that is clicked
    /*--------------------------------------------------------------*/
    function sort(oTH)
    {
        curSortCol = oTH.cellIndex;
        sortType = oTH.abbr;
        trs = table.tBodies[0].getElementsByTagName("tr");

        //set the get function
        setGet(sortType)

        // it would be nice to remove this to save time,
        // but we need to close any rows that have been expanded
        for(var j=0; j<trs.length; j++)
        {
            if(trs[j].className == 'detail_row')
            {
                closeDetails(j+2);
            }
        }

        // if already sorted just reverse
        if(prevSortCol == curSortCol)
        {
            oTH.className = (oTH.className != 'descend' ? 'descend' : 'ascend' ); // reversed from original
            reverseTable();
        }
        // not sorted - call quicksort
        else
        {
            oTH.className = 'descend'; // reversed from original
            if(ths[prevSortCol].className != 'exc_cell'){ths[prevSortCol].className = '';}
            quicksort(0, trs.length);
        }
        prevSortCol = curSortCol;
    }

    /*--------------------------------------------------------------*/
    // Sets the GET function so that it doesnt need to be
    // decided on each call to get() a value.
    // @param: colNum - the column number to be sorted
    /*--------------------------------------------------------------*/
    function setGet(sortType)
    {
        switch(sortType)
        {
            case "link_column":
                get = function(index){
                    return  getCell(index).firstChild.firstChild.nodeValue;
                };
                break;
            default:
                get = function(index){    return getCell(index).firstChild.nodeValue;};
                break;
        };
    }

    /*-----------------------EXCHANGE-------------------------------*/
    //  A complicated way of exchanging two rows in a table.
    //  Exchanges rows at index i and j
    /*--------------------------------------------------------------*/
    function exchange(i, j)
    {
        if(i == j+1) {
            table.tBodies[0].insertBefore(trs[i], trs[j]);
        } else if(j == i+1) {
            table.tBodies[0].insertBefore(trs[j], trs[i]);
        } else {
            var tmpNode = table.tBodies[0].replaceChild(trs[i], trs[j]);
            if(typeof(trs[i]) == "undefined") {
                table.appendChild(tmpNode);
            } else {
                table.tBodies[0].insertBefore(tmpNode, trs[i]);
            }
        }
    }

    /*----------------------REVERSE TABLE----------------------------*/
    //  Reverses a table ordering
    /*--------------------------------------------------------------*/
    function reverseTable()
    {
        for(var i = 1; i<trs.length; i++)
        {
            table.tBodies[0].insertBefore(trs[i], trs[0]);
        }
    }

    /*----------------------QUICKSORT-------------------------------*/
    // This quicksort implementation is a modified version of this tutorial:
    // http://www.the-art-of-web.com/javascript/quicksort/
    // @param: lo - the low index of the array to sort
    // @param: hi - the high index of the array to sort
    /*--------------------------------------------------------------*/
    function quicksort(lo, hi)
    {
        if(hi <= lo+1) return;

        if((hi - lo) == 2) {
            if(get(hi-1) > get(lo)) exchange(hi-1, lo);
            return;
        }

        var i = lo + 1;
        var j = hi - 1;

        if(get(lo) > get(i)) exchange(i, lo);
        if(get(j) > get(lo)) exchange(lo, j);
        if(get(lo) > get(i)) exchange(i, lo);

        var pivot = get(lo);

        while(true) {
            j--;
            while(pivot > get(j)) j--;
            i++;
            while(get(i) > pivot) i++;
            if(j <= i) break;
            exchange(i, j);
        }
        exchange(lo, j);

        if((j-lo) < (hi-j)) {
            quicksort(lo, j);
            quicksort(j+1, hi);
        } else {
            quicksort(j+1, hi);
            quicksort(lo, j);
        }
    }
}

Second part, in the page with the tables:


function init() {
    var Table1Sorter = new TSorter;
    var Table2Sorter = new TSorter;

    Table1Sorter.init('score-x-year-for-one-patho');
    Table2Sorter.init('score-x-patho-in-one-year');
}

I tried putting this in several places:


if (table.Id == 'score-x-year-for-one-patho')
            var prevSortCol = '0';
else if (table.Id == 'score-x-patho-in-one-year')
            var prevSortCol = '3';

but that doesn’t work. I either get a Firebug report that prevSortCol is not defined, or it keeps having the same value for all tables.

Anyone know how this should be done?

I’m not sure if this has much to do with your issue, but this is wrong:

table.Id == 'score-x-year-for-one-patho'

The id attribute may not be capitalized.

Better would be:

if (table.id === 'score-x-year-for-one-patho') {
  var prevSortCol = '0';
} else if (table.id == 'score-x-patho-in-one-year') {
  var prevSortCol = '3';
}

Other than that, could you post a link to a page where I could see this problem?

Thanks again for jumping in, Pullo.

Correcting the capitalization makes some, but not enough difference. Now, Firebug no longer says that prevSortCol is not defined, but its value stays set to 3 for all tables. Here is the project I’m working on: http://www.gezondezorg.org/pzp.html. There will be more tables, with sometimes very different characteristics.

The script is from this site: http://www.terrill.ca/sorting/. There is documentation available there, but that is beyond my understanding. If it it all offers the option to have a dynamic prevSortCol value.

Hi there,

There is no obvious option you can pass in to the library with which to specify the column to sort by.
But before we go pulling the library apart to try and make it do what we want, there is a little hack we could employ.

What you do is set things up so that you have multiple sortable tables on the same page.
Then, in your HTML you apply a class to the <th> element you want to sort by, e.g.:

<thead>
  <tr>
    <th abbr="link">ID</th>
    <th abbr="input_text">NAME</th>
    <th abbr="image_number" [B]class="columnToSortBy"[/B]>PRICE</th>
    <th>LATITUDE</th>
    <th>LONGITUDE</th>
    <th abbr="link">ADDRESS</th>
  </tr>
</thead>

Then, at the foot of your page, you get a reference to any elements that have this class applied to them and use JavaScript to simulate a click on them.

That would look like this:

var cols = document.querySelectorAll(".columnToSortBy");
for(var i=0, len=cols.length; i<len; i++){
  cols[i].click();
}

Et voilà, the desired effect has been achieved :slight_smile:

I did as you suggested (and I now uploaded the separate script file to my project, which I forgot previously). See http://www.gezondezorg.org/pzp.html. However, I am now getting a reference error report from Firebug. Also, it doesn’t solve the problem, which I will describe in more practical terms:

Scroll down to the first table with the orange header background. If you click on the first column header, which is the HTML-sorted column, you will see that nothing happens. You have to click once more to have the order of that column reversed. If you click the HTML-sorted column of the table below that, which is the fourth column, you will see that the sorting order is reversed immediately.

Seemingly a minor problem, but it just looks odd if you have to click the default order column twice in some tables to have its sorting order reversed.

Hi,

The reason why this was not working was that you had this in one of your <th> elements: onclick="alert(prevSortCol)" and the variable prevSortCol was not defined.

However, this doesn’t solve your other problem that you have to click twice on a column to sort it in reverse order.

I have made a very simple example to demonstrate the problem:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Zorg-performance-zoekpagina</title>
</head>

<body>
    <table id="score-x-year-for-one-patho" border="1" cellpadding="5">
        <thead>
            <tr>
                <th>Jaar</th>
                <th>Patiënttevredenheidsscore</th>
                <th>Ziektelastscore</th>
                <th>Gewogen totaalscore</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>2013</td>
                <td>8,0</td>
                <td>6,2</td>
                <td>6,8</td>
            </tr>
            <tr>
                <td>2012</td>
                <td>7,4</td>
                <td>6,1</td>
                <td>6,5</td>
            </tr>
            <tr>
                <td>2011</td>
                <td>6,5</td>
                <td>5,1</td>
                <td>5,6</td>
            </tr>
            <tr>
                <td>2010</td>
                <td>5,9</td>
                <td>5,2</td>
                <td>5,9</td>
            </tr>
        </tbody>
    </table>

    <script src="http://www.terrill.ca/sorting/TSorter_1_example.js"></script>
    <script>
    function init() {
      var Table1Sorter = new TSorter;
      Table1Sorter.init('score-x-year-for-one-patho');
    }
    window.onload = init;
  </script>
</body>
</html>

As you can see, “Jaar” is sorted in descending order (largest first) when the page loads.
After the first click on “Jaar”, the plugin sorts the column in descending order (largest first), which is why you see no change.
I guess it is assuming that you maybe have 2013 - 2011 - 2012 - 2010 or something like that, where the years are not ordered.
It needs to sort them in descending order once (obviously), but doesn’t seem to be clever enough to realise that they are already in the correct order.

You can see this illustrated if you click “Ziektelastscore”
The first two numbers don’t change, but the bottom two swap position.

At this point, if you don’t mind using jQuery, I would recommend using something like this, as it works as you want out of the box.

Here’s an example:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Zorg-performance-zoekpagina</title>
    <style>table{ margin: 15px; }</style>
</head>

<body>
    <table id="table1" border="1" cellpadding="5">
        <thead>
            <tr>
                <th>Jaar</th>
                <th>Patiënttevredenheidsscore</th>
                <th>Ziektelastscore</th>
                <th>Gewogen totaalscore</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>2013</td>
                <td>8,0</td>
                <td>6,2</td>
                <td>6,8</td>
            </tr>
            <tr>
                <td>2012</td>
                <td>7,4</td>
                <td>6,1</td>
                <td>6,5</td>
            </tr>
            <tr>
                <td>2011</td>
                <td>6,5</td>
                <td>5,1</td>
                <td>5,6</td>
            </tr>
            <tr>
                <td>2010</td>
                <td>5,9</td>
                <td>5,2</td>
                <td>5,9</td>
            </tr>
        </tbody>
    </table>

    <table id="table2" border="1" cellpadding="5">
        <thead>
            <tr>
                <th>Jaar</th>
                <th>Patiënttevredenheidsscore</th>
                <th>Ziektelastscore</th>
                <th>Gewogen totaalscore</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>2013</td>
                <td>8,0</td>
                <td>6,2</td>
                <td>6,8</td>
            </tr>
            <tr>
                <td>2012</td>
                <td>7,4</td>
                <td>6,1</td>
                <td>6,5</td>
            </tr>
            <tr>
                <td>2011</td>
                <td>6,5</td>
                <td>5,1</td>
                <td>5,6</td>
            </tr>
            <tr>
                <td>2010</td>
                <td>5,9</td>
                <td>5,2</td>
                <td>5,9</td>
            </tr>
        </tbody>
    </table>

    <table id="table3" border="1" cellpadding="5">
        <thead>
            <tr>
                <th>Jaar</th>
                <th>Patiënttevredenheidsscore</th>
                <th>Ziektelastscore</th>
                <th>Gewogen totaalscore</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>2013</td>
                <td>8,0</td>
                <td>6,2</td>
                <td>6,8</td>
            </tr>
            <tr>
                <td>2012</td>
                <td>7,4</td>
                <td>6,1</td>
                <td>6,5</td>
            </tr>
            <tr>
                <td>2011</td>
                <td>6,5</td>
                <td>5,1</td>
                <td>5,6</td>
            </tr>
            <tr>
                <td>2010</td>
                <td>5,9</td>
                <td>5,2</td>
                <td>5,9</td>
            </tr>
        </tbody>
    </table>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="http://tablesorter.com/__jquery.tablesorter.min.js"></script>
    
    <script>
        // Default initialization
        $("#table1").tablesorter();

        // Initially sorted by column 2 in ascending order
        $("#table2").tablesorter({sortList: [[1,0]]});

        // Initially sorted by column 2 in ascending order
        $("#table3").tablesorter({sortList: [[1,1]]});
    </script>
</body>
</html>

You is one great neighbor, Pullo!

I indeed forgot to delete the onclicks in the <th> tags, which I had used to see where exactly it went wrong with the vanilla script. And which did not go well with your suggestion. Deleting them indeed solved the reference error.

And I love your jQuery solution! I normally prefer vanilla script, but this clearly justifies using the jQuery library. If it were only because it works, and we could probably not easily have solved the problem with the vanilla script. I doubt even its maker could have.

I already nominated you this year, but as soon as I have recovered from the New Year’s Eve champagne, I will nominate you again in 2014! Cheers! :smiley:

PS: to return the favor, in case you would ever have problems with vertical centering in CSS, I wrote a tutorial on it. (The tut on how to target IE will undergo a major update in a while, including how to target mobile browsers on the different platforms.)

Hi there,

I’m glad it works for you. Thanks for taking the time to report back.

Thank you :slight_smile:
You could also show your appreciation by voting in the end of year awards (which are starting at the beginning of next week, I believe), not just for me, but for anyone you recognize who has helped you around the forums in the past year.

Will do.

FYI: I found out another nice aspect of the jQuery script: it adds classes, rather than replace 'em like the other script did. That makes the HTML/CSS easier. And the fact that the default sorted column can be set with the script, rather than having to HTML-construct every sortable table differently, makes it easier for the back-end developers. Great stuff! :slight_smile: