FixedHeaders v1.0.0 - "Freeze" the column titles at the top of the table

FixedHeaders v1.0.0 - "Freeze" the column titles at the top of the table

allanallan Posts: 61,972Questions: 1Answers: 10,160 Site admin
edited September 2009 in Announcements
Hello all,

This is a feature which has been requested a surprising number of times recently, so I've put together an add-on script for DataTables which will "freeze" the column headers at the top of the table - i.e. even when the user scrolls down the table, the column titles will be shown floating at the top of the page.

You can see an example and how to initialise the add-on here:
http://datatables.net/release-datatables/extras/FixedHeader/

This will be included in the next DataTables release, but for now you can get the source from here:
http://datatables.net/release-datatables/extras/FixedHeader/FixedHeader.js

Performance seems to be quite good, particularly on Webkit based browsers, where it is exceptionally smooth - in Firefox and IE the redraw can be seen in brief flashes, but it's probably about as good as it will get without using position:fixed or something like that (which would bring with it, it's own set of problems).

All comments and suggestions are most welcome.

Regards,
Allan

Replies

  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Hi Allan, really happy to see this new feature! Thank you!


    J.
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Allan, some feedback:

    1. It would be good if the header didn't flash in FF/IE, which I assume could be sorted with position:fixed (a la the Facebook presence bar). However, I assume the problem here is that you need to detect when to start "fixing" the position of the cloned header. Attaching an offset() call to the window.scroll event would be very computationally expensive, I imagine.

    2. I think it's very useful the the fnUpdate function is exposed, as my FixedHeader needs updating both when I add/remove columns and when my page changes in length (altering the offset of the table). It would be good if these changes were picked up on by the plugin itself (another reason why a dynamic detection of table header position would be a good thing, if it could be done without the significant performance hit alluded to above).


    J.
  • allanallan Posts: 61,972Questions: 1Answers: 10,160 Site admin
    Hi,

    Thanks very much for the feedback - very useful indeed!

    1. The reason I didn't go with position:fixed is that (as far as I understand) it's really rather broken in IE6 (I think IE7 fixed it). But I'm trying to have IE6 as an A grade supported browser (and least for now!). position:fixed, in combination with position:absolute would probably be the best way of doing things. I'd think doing anything interaction with the DOM is quite expensive in a scroll event - so the more that could be avoided the better. I'll look into what might be do-able with position:fixed. Another option might be to have the title bar 'tween' itself into location, thus making the 'flash' into a smooth transition. I think I'd find that quite a annoying on a site myself...

    2. Yup - this is exactly why I exported fnUpdate :-). There isn't actually way way for DataTables to inform plug-ins that something has happened (at the moment), and as such this function must be called manually. The only way around it would be to attach fnUpdate() to fnDrawCallback() - and that would probably work, and the end users would likely not notice anything - but it doesn't seem a very 'clean' way of doing it to me...

    Regards,
    Allan
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Hi Allan,

    1. Have you looked into using CSS expressions to handle IE6 specifically? There's an example here: http://bytes.com/topic/html-css/answers/577825-frozen-locked-html-table-header. Also, looking at a Facebook page (when logged in) using IE6 could be very telling, as the "presence bar" at the bottom of the page stays fixed in place.

    I found a general discussion on fixed table headers here (but no mention of position:fixed): http://stackoverflow.com/questions/486576/frozen-table-header-inside-scrollable-div

    2. I've found that calling fnUpdate doesn't actually reset my FixedHeader's offset, which I need for when I'm inserting things in the DOM above it. Am I using this correctly?

    [code]
    oTable.fixedHeader = new $.fn.dataTablesExt.FixedHeader(oTable);
    ...update the DOM...
    oTable.fixedHeader.fnUpdate();
    [/code]

    Thanks,


    J.
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Also, on the subject of fnDrawCallback, it looks appealing, but doesn't quite work as I'd expect:

    1. hiding a column doesn't trigger the callback
    2. filtering triggers the callback multiple times (1 or 6 in my experiment)


    J.
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Allan,

    Having had the FixedHeader plugin in use for a while, I would say that using an eased slide to the new location would be a fine way round the header flashing problem for me. In fact, I think it would highlight the feature and people would like that.


    J.
  • allanallan Posts: 61,972Questions: 1Answers: 10,160 Site admin
    Hi jnthnlstr,

    Thanks for all the details. I've had a quick experiment with position:fixed, and it works great in most browsers - expect IE6 which it just goes horrible. It would be great if I could hack a way around that in IE as it could be made very efficient - more research needed :-)

    About the point for not updating the offsetWidth - no you are right - it doesn't do this. The next revision will.

    Allan
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Allan,

    Glad you've had some success with the position:fixed method! Just a thought - would it be possible to use the existing method for IE and the position:fixed method for other browers?


    J.
  • bobs325bobs325 Posts: 3Questions: 0Answers: 0
    This is a neat feature, but has anybody looked into freezing columns instead of rows?

    The best example I've found of this is here:
    http://www.dotnetoutsource.com/Download/jQuery_FixedTable/jQuery_FixedTable_Demo.htm

    I really love DataTables and have it extensively integrated in my project, but we also have a huge need of having 2 fixed columns at the left of the table. The plugin above (and other hacks) result in multiple tables in various divs, which needless to say won't allow DataTables integration without some serious hacking!
  • allanallan Posts: 61,972Questions: 1Answers: 10,160 Site admin
    Hi bobs325,

    Interesting thought freezing the columns as well as the header. I don't see any reason why it wouldn't be possible - indeed if you have a look at the code for FixedHeaders you'll see that it's actually quite simple, and could readily be modified for doing columns as well (indeed it might even be simpler in some aspects since it won't have event handlers to pass down - the sorting). You'd probably need to update the frozen columns on each table draw, but that can easily be done using fnDrawCallback and a simple API function.

    @jnthnlstr: Yup - that's exactly what I was thinking. Fixed positioning for everything but IE6, which will get a "reduced" experience. Their own fault for using IE6 in this day and age anyway :-). Coding for that will be hopefully starting soon :-)

    Regards,
    Allan
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Hi Allan,

    Thought I'd let you know I've found (and hopefully fixed) an IE bug with FixedHeaders.

    At line 165:
    [code]
    $("thead:eq(0)>tr th:eq("+i+")", _nCTable)[0].style.width =
    parseInt($(this).css('width'))+"px";
    [/code]
    The value of 'width' returned from the TH by IE is 'auto', rather than the pixel value, which ends up causing an error.

    This can be fixed by doing this:
    [code]
    var width = $(this).width();
    $("thead:eq(0)>tr th:eq("+i+")", _nCTable).width(width);
    [/code]

    For some reason, this code a few lines down doesn't seem to be causing the same error (although I'm not sure as I've surrendered access to a Windows machine for the evening):
    [code]
    $("thead:eq(0)>tr td", _oSettings.nTable).each( function (i) {
    $("thead:eq(0)>tr td:eq("+i+")", _nCTable)[0].style.width =
    parseInt($(this).css('width'))+"px";
    } );
    [/code]
    I haven't been able to pin-point why this happens, as the web seems a bit short on moans about IE not supporting the 'width' property. I was worried it was a quirks mode problem, but haven't tested that.


    J.
  • allanallan Posts: 61,972Questions: 1Answers: 10,160 Site admin
    @jnthnlstr: Nice one. Thanks for sharing that! I wonder if it might be faster to just use offsetWidth rather than $.css(). I can't remember why I did it that way originally - I'll have an experiment with it :-)

    Allan
This discussion has been closed.