Search code examples
jqueryajaxtablesorter

Tablesorter not initializing after Ajax replaces HTML


I'm using Mottie's Tablesorter jQuery addon: https://mottie.github.io/tablesorter/docs/

I'm using the pager plugin with server-side processing, and I'm building the HTML on the server and sending it back with the JSON result for the pager plugin's ajaxProcessing function.

My table HTML gets loaded correctly, but Tablesorter doesn't do its magic (adding the colgroup for nicely-spaced columns, and updating the THEAD to make the columns sortable and to enable the filter dropdowns I added with my HTML.)

Here's a snip of the HTML I start with:

<table class="tableMain" id="scenarioTable">
    <thead>
        <tr class="tableRowHeader">
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                <div class="loadingCircle"></div>
            </td>
        </tr>
    </tbody>
</table>

(The "loadingCircle" class is just a CSS placeholder animation; "tableMain" and "tableRowHeader" are style classes defined elsewhere.)

Here's my Javascript:

$(function () {
    $("#scenarioTable").tablesorter({
        cancelSelection: true,
        debug: true,
        emptyTo: "zero",
        serverSideSorting: true,
        showProcessing: true,
        sortReset: true,
        theme: "custom",
        widthFixed: true,
        widgets: ["filter", "zebra"],
        widgetOptions:
            {
                filter_childRows: false,
                filter_columnFilters: true,
                filter_formatter: null,
                filter_hideFilters: false,
                filter_reset: '.clearFilters',
                filter_serversideFiltering: true
            }
    })
    .tablesorterPager({
        container: $(".scenarioPager"),
        ajaxObject: {
            type: 'POST',
            dataType: 'json',
            data: { scenarioID: 1000 },
            success : function(){ $("#scenarioTable").trigger("update"); }
        },
        ajaxProcessing: function(result, table, xhr){
            if (result && result.hasOwnProperty('mScenarioTableHTML')) {
                var toReturn = {
                    total : result["mTotalRows"],
                    filteredRows : result["mTotalFilteredRows"]
                }
                $(table).html(result["mScenarioTableHTML"]);
                return toReturn;
            }
        },
        ajaxUrl: "my URL goes here",
        page: 0,
        pageReset: 0,
        processAjaxOnInit: true,
        size: 1000,
    });
});

So when the page loads, Tablesorter updates the table HTML to this, as expected:

<table class="tableMain tablesorter tablesorter-custom tablesorter749b92e50ae53 hasFilters tablesorter-processing" id="scenarioTable" role="grid" aria-describedby="scenarioTable_pager_info">
    <colgroup class="tablesorter-colgroup"><col style="width: 100%;"></colgroup>
    <thead>
        <tr class="tableRowHeader" role="row">
        </tr>
    </thead>
    <tbody aria-live="polite" aria-relevant="all"></tbody>
</table>

Then my ajaxProcessing function replaces the COLGROUP, THEAD, and TBODY tags with the HTML I send from the server, and the HTML ends up looking like this:

<table class="tableMain tablesorter tablesorter-custom tablesorter792090cf9b53c hasFilters" id="scenarioTable" role="grid" aria-describedby="scenarioTable_pager_info">
    <thead>
        <tr class="tableRowHeader">
            <th class="filter-select">
                Trial #
            </th>
            <th class="filter-select">
                Time (sec)
            </th>
        </tr>
        <tr>
            <td>
                <select name="trial" id="trial">
                  <option value="" selected="selected"> </option>
                  <option value="1">1</option>
                  <option value="2">2</option>
                </select>
            </td>
            <td>
                <select name="time" id="time">
                  <option value="" selected="selected"> </option>
                  <option value="10.5">10.5</option>
                  <option value="13.4">13.4</option>
                </select>
            </td>
        </tr>
    </thead>
    <tbody>
        <tr class="odd">
            <td id="101" class="notFlagged">
                1
            </td>
            <td id="102" class="flagged">
                13.4
            </td>
        </tr>
        <tr class="even">
            <td id="103" class="notFlagged">
                2
            </td>
            <td id="104" class="notFlagged">
                10.5
            </td>
        </tr>
    </tbody>
</table>

So Tablesorter only adds the "odd" and "even" classes to the TR tags for zebra striping, and nothing else. The rest of the HTML is exactly what I send from the server.

Is there a way to have Tablesorter update the HTML I load, or does Tablesorter have to build the HTML itself in order to add in the sorting and filtering stuff?


Solution

  • The pager ajaxProcessing function should not replace the entire table. If you want to update the header, it is better to include the same number of columns (look at the HTML of this demo). Instead return a headers value from the ajaxProcessing function as described in the documentation for returning a object.

    If you must update the entire table, don't use the ajaxProcessing function. Instead bind to the pager events, then:

    • Detroy the current tablesorter instance, and reinitialize it after the pager completes.
    • Or, use updateAll to update tablesorter's thead and tbody content. This isn't recommended because it is still problematic and may lead to a memory leak.