Simple Resizable Table Scroller

I needed a simple scrolling, sorting table for a project, and the available grid controls (e.g.: jqGrid, flexigrid) were really too heavy for my limited needs. I didn’t need inline editing, grouping, or any of the other advanced features these grids provide.  Christian Bach’s tablesorter plugin (www.tablesorter.com) was a great  alternative, but my project required the table fit in a window of limited height. I needed a way to add scrolling to tablesorter.

Fortunately, tablesorter’s ‘widget’ architecture makes it easy to add functionality as it is needed. This widget duplicates the table header and wraps the original table in a scrolling div. It then hides the original table’s header. Header cell clicks are trapped and passed to the original table via tablesorter’s ‘sorton’ event.

You can find a working example here.
Download the js file here. I’ve tested it in IE 7,8, and 9; FireFox 7; and Chrome 15.

Adding the scroller is as simple as including ‘scroller’ in the tablesorter widget list. The scroller also adds a ‘scrollHeight’ option to specify the height of the window the table scrolls within. scrollHeight has a default value of 250px.

$('table.tablesorter').tablesorter({
    scrollHeight: 300,
    widgets: ['zebra','scroller']
});

Fluid Layout

One drawback of this method for making a table scroll is that it fixes the width of the header cells so they do not change if the table is resized. Another project requirement was for a fluid layout that expanded and contracted with the browser window. Much of the code in the scroller widget is responsible for handling the header resize. Each time a resize event is triggered, the widget first allows the original table to find its desired width. It then loops through each header cell, setting the width to match that of the corresponding cell in the underlying table.

To enable this, the scroller exposes a resizeWidth method that can be called when the browser window is resized. However, most browsers running on Windows 7 trigger the resize event repeatedly as long as the browser window size is changing. To prevent the resizeWidth method from being called repeatedly, this page uses setTimeout to create a new resizeEnd event that is triggered only after the user stops resizing. It then calls the resizeWidth method when this new event is triggered.

$(document).ready(function() {
    //Setup window.resizeEnd event
    $(window).bind('resize', window_resize);
    $(window).bind('resizeEnd', function (e) {
        /*
           IE calls resize when you modify content.
           We have to unbind the resize event
           so we don't end up with an infinite loop.
           We can rebind after we're done.
        */
        $(window).unbind('resize', window_resize);
        $('table.tablesorter').each(function(n, t) {
            if (typeof t.resizeWidth === 'function') t.resizeWidth();
        });
        $(window).bind('resize', window_resize);
    });
});

function window_resize() {
    if (this.resize_timer) clearTimeout(this.resize_timer);
    this.resize_timer = setTimeout(function () {
        $(this).trigger('resizeEnd');
        }
      , 250
    );
}

Note that the changes to the header table width will trigger the resize event in IE. To prevent this from creating an infinite loop, this code detaches the window_resize handler before adjusting the table width. It then reattaches the handler once the resize has
completed.

Leave a Reply