Tablesorter jQuery Plugin - a fix

Updated Airshow 0 Tallied Votes 847 Views Share

Tablesorter (currently v2.0.5) includes an "update" method. This method keeps a Tablesorter object up to date with dynamic changes made to its table(s).

Like other Tablesorter methods "update" is implemented in the form of a custom event.

A typical method call would be $table.trigger("update"); , where $table is a jQuery object.

For some reason unknown to me, the "update" event code is written inside a setTimeout(function(){...}, 1) structure. Presumably this overcomes a problem in some browser or other.

This works fine within itself but means that statement(s) immediately following a .trigger("update") call will be executed before the "update". This is no good when the following statement(s) depend on the update being complete, notably .trigger("sorton", ...) , which (re)implements a sort.

The following patch overcomes the shortcoming by implementing within the "update" method:

  • a way to re-execute the last user-selected sort
  • a generalised way to execute any code of your choice.

For usage instructions, see comment block in code.

Airshow

//--find
                    /*
                    $this.bind("update", function () {
                        var me = this;
                        setTimeout(function () {
                            // rebuild parsers.
                            me.config.parsers = buildParserCache(me, $headers);
                            // rebuild the cache map
                            cache = buildCache(me);
                        }, 1);
                    */
//--replace with
                    /* 
                     * Fix by Airshow, 07 August 2011
                     * Allows post-update actions:
                     * (a) an optional table re-sort.
                     * (b) a callback function.
                     * Sample call with re-sort:
                     *   jqueryObj.trigger({type:'update', resort:true});
                     * Sample call with callback:
                     *   jqueryObj.trigger({type:'update', callback: function(config) {
                     *     $(this).trigger("sorton", [config.sortList]);
                     *   }});
                     * NOTE: The second sample call is functionally identical to the first.
                     */
                    $this.bind("update", function (e) {
                        var me = this;
                        setTimeout(function () {
                            // rebuild parsers.
                            me.config.parsers = buildParserCache(me, $headers);
                            // rebuild the cache map
                            cache = buildCache(me);
                            if(e.resort||e.re_sort) { $(me).trigger("sorton", [config.sortList]); }
                            if(e.callback) { e.callback.call(me, config); }
                        }, 1);
                    //--end fix

*incorporating mikehershey's correction kindly offered below: 22_05_20-12*

Dani AI

Generated

A concise, up-to-date summary and practical fix notes that build on 's patch and the follow-ups from and others.

The original patch solved a timing problem caused by Tablesorter's internal use of a short timeout by adding a post-update "resort" and a callback hook. That pattern (resort flag + callback + an event emitted after update) is now part of modern Tablesorter: the core update flow accepts a resort parameter (or an explicit sort list) and a callback, and the plugin also exposes an updateComplete event you can bind to. Upgrading to a recent Tablesorter release removes the need for a custom patch in most cases. (mottie.github.io)

If the pager is being used and pages look "unbalanced" after deleting rows (the symptom described), the root cause is the pager/cache interaction: when the pager is configured to remove rows from the DOM, only the visible page exists in the DOM and the remaining rows live in the plugin cache. To safely change rows while using the pager, repopulate the DOM from the cache first, then make the DOM edits, then tell Tablesorter to rebuild its cache and optionally reapply the sort. The plugin provides an appendCache helper for this exact workflow. (mottie.github.io)

Practical sequence (no plugin edits required if you can upgrade):

  • If using the pager with removeRows, call the pager/appendCache step so the DOM contains all rows.
  • Make the DOM change (remove or insert rows).
  • Trigger Tablesorter's update flow and either pass the resort flag or use the callback/updateComplete to reapply sorting / re-initialize pager rendering; for adding rows prefer the addRows API when using the pager.
    If upgrading is impossible, 's patch is a reasonable fallback, but prefer the built-in methods when available. (mottie.github.io)

Notes: always trigger update on the actual table element (not an undefined variable) and use delegated event binding appropriate to your jQuery version.

mikehershey 13 Newbie Poster

Nice work! I just spent a ton of time trying to fix this bug. Just one little issue with your documentation here your example call with call back should be:

jqueryObj.trigger({type:'update', callback : function(config){
$(this).trigger("sorton", [config.sortList]);
}});

commented: Thanks Mike for correcting my error. +13
Airshow 425 WiFi Lounge Lizard Team Colleague

Mike,

I'm so glad my patch has been of use to you.

Many thanks for the correction to the documentation.

To future users of the patch: Please use mikehershey's version of the "sample call with feedback".

Airshow

alanpuccinelli 0 Newbie Poster

Man, I was banging my head against the wall on this one. They should really implement this into the source. Really frustrating if you're trying to replace the entire set of table data and then re-sort.

Thanks so much for posting!

Airshow 425 WiFi Lounge Lizard Team Colleague

It's very gratifying that folk are registering here at Daniweb just to say thank you. More power to your elbow guys & gals.

The author of Tablesorter has been made aware via his Google code repository.

Airshow

mano7859 0 Newbie Poster

Hi,

Thanks for this code.

I got a probleme with it.
I've modified the 'jquerty.tablesorter.js' with your patch.
When i applied it my table doesn't refresh after deleting a row.
Please help !!!

This is my 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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Document sans titre</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="js/jquery.tablesorter.pager.js"></script>
<script type="application/javascript">
$(document).ready(function() { 

$('table').tablesorter({ sortList: [ [0, 0] ], });
 $("table").tablesorterPager({container: $("#pager")}); 


    $("table").delegate('button.remove', 'click' ,function(){ 
        $(this).closest('tr').remove();
        jqueryObj.trigger({type:'update', resort:true});
     }); 

});

</script>
</head>

<body>
<div id="updateTable">
<table id="myTable" class="tablesorter">
    <thead>
        <tr class='test'>
            <th>Nom</th>
            <th>Prénom</th>
            <th>Supprimer</th>
        </tr>
    </thead>

    <tbody>
        <tr>
            <td>Martin</td>
            <td>Alexandre</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Martin</td>
            <td>Thomas</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Dupont</td>
            <td>Edwige</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Durand</td>
            <td>Philippe</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Victor</td>
            <td>Emeline</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Jones</td>
            <td>Cris</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Swain</td>
            <td>Phil</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Bruce</td>
            <td>Noemi</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Smith</td>
            <td>Arnold</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Cavite</td>
            <td>Olivier</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Estebriand</td>
            <td>César</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Polaris</td>
            <td>Benoît</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Roger</td>
            <td>Manon</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
    </tbody>
</table>


    <!-- pager --> 
    <div id="pager" class="pager"> 
      <form> 
        <img src="first.png" class="first"/> 
        <img src="prev.png" class="prev"/> 
        <span class="pagedisplay"></span> <!-- this can be any element, including an input --> 
        <img src="next.png" class="next"/> 
        <img src="last.png" class="last"/> 
        <select class="pagesize"> 
          <option selected="selected" value="10">10</option> 
          <option value="20">20</option> 
          <option value="30">30</option> 
          <option value="40">40</option> 
        </select> 
      </form> 
    </div>

</div>
</body>
</html>
Airshow 425 WiFi Lounge Lizard Team Colleague

A few points ...

  1. Line 12 has an unwanted comma.

  2. I'm not 100% sure that row removal requires a resort. Surely the remaining rows just stay in their current sort order. There's no harm in doing a re-sort but is it necessary, mmmm?

  3. Assuming a resort is necessary, lines 16-19 should read as follows:

With jQuery <1.7 :

$("table").delegate('button.remove', 'click' ,function(){
    var $this = $(this);
    var $table = $this.closest('table');
    $this.closest('tr').remove();
    $table.trigger({type:'update', resort:true});
 });

With jQuery >=1.7, .delegate() is deprecated in favour of a particular use of .on(), therefore :

$("table").on('click', 'button.remove', function() {
    var $this = $(this);
    var $table = $this.closest('table');
    $this.closest('tr').remove();
    $table.trigger({type:'update', resort:true});
});
mano7859 0 Newbie Poster

Thank you Airshow for your answer and to take time to resolve my problem.

I've tried that you purposed me but I've obtained the same result.
I'm explaining:
We have 10 rows (page 1) and 5 rows (page 2). After removing a row, I have 9 rows (page 1) and 5 rows (page 2). The logic was to have 10 rows (page1) and 4 rows (page2).

Could you help me please? Thanks

This is my code after your advising:

<!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">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Title page</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="js/jquery.tablesorter.pager.js"></script>

<script type="application/javascript">
    $(document).ready(function() { 
        $("table").tablesorter({ sortList: [ [0, 0] ], });
        $("table").tablesorterPager({container: $("#pager")}); 

        $("table").delegate('button.remove', 'click' ,function(){
            var $this = $(this);
            var $table = $this.closest('table');
            $this.closest('tr').remove();
            $table.trigger({type:'update', resort:true});
         });
    });
</script>


<body>
<div id="updateTable">
<table id="myTable" class="tablesorter">
    <thead>
        <tr class='test'>
            <th>Nom</th>
            <th>Prénom</th>
            <th>Supprimer</th>
        </tr>
    </thead>

    <tbody>
        <tr>
            <td>Martin</td>
            <td>Alexandre</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Jones</td>
            <td>Cris</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <tr>
            <td>Swain</td>
            <td>Phil</td>
            <td><button class="remove" title="Supprimer l'enregistrement">X</button></td>
        </tr>
        <!-- Other datas -->

    </tbody>
</table>


    <!-- pager --> 
    <div id="pager" class="pager"> 
      <form> 
        <img src="first.png" class="first"/> 
        <img src="prev.png" class="prev"/> 
        <span class="pagedisplay"></span> <!-- this can be any element, including an input --> 
        <img src="next.png" class="next"/> 
        <img src="last.png" class="last"/> 
        <select class="pagesize"> 
          <option selected="selected" value="10">10</option> 
          <option value="20">20</option> 
          <option value="30">30</option> 
          <option value="40">40</option> 
        </select> 
      </form> 
    </div>

</div>
</body>

</html>
punknroll 0 Newbie Poster

Hey man, I have been struggling with this for hours. Your code should go to the official version. greetz

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.