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

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

allanallan Posts: 61,795Questions: 1Answers: 10,115 Site admin
edited October 2009 in General
Hello all,

I've done a bit of work on FixedHeaders in order to make the display of the header as smooth as possible - and it's generally been very successful. There is a massive improvement in display speed in Firefox and IE8 specifically (Webkit was already smooth), but all browsers should see a big improvement due to the reduced DOM queries and updates.

One thing to note is that IE6 and IE7 do not benefit much from this update (there are some small optimisations), due to lack of position:fixed support in IE6 and a bug in IE7. As such, these two browsers use the old method.

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

Many thanks go to jnthnlstr on the forum for input on this plug-in for DataTables.

Regards,
Allan

Replies

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

    Great news. I'm playing with this now and I thought I'd mention that, on FF and Safari, the widths of the cloned header's cells jump to be a little bit bigger than they should be. On your example, linked to above, this doesn't happen, so I don't know what's going on there. I'm looking into it now.

    On another note, I'd really like you to go into detail about the problem that was caused with IE cloning event handlers as well as nodes. I'm being frustrated by my attempts to get FixedHeader and dragColumns (that I've been posting about) to work together - the passthrough of a mousedown event by FixedHeader is somehow causing the FixedHeader event handler to fire in an infinite loop (I hacked FixedHeader to passthrough mousedown events too).

    Thanks,


    J.
  • jnthnlstrjnthnlstr Posts: 27Questions: 0Answers: 0
    Ok, I've cracked the width problem - it comes from setting width:100% on the table - once the header is pulled out of the flow with position:fixed, that inherited width seems to apply to the entire page.

    I've fixed this for me by changing width:100% to width:inherit on the table.

    I think another way to do it could be to specify a width for the cloned header, based on the width of its clonee.


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

    Good to hear you got it sorted. I'm intrigued by this:

    > I hacked FixedHeader to passthrough mousedown events too

    Do you mean that you used the same "passthrough" as I did for clicking, or is it a 'true' passthrough - which I'm not sure how it would work due to the absolute positioning on the elements...

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

    Yes, I used the same passthrough as you did. In my final version of dragColumns [1], I'm not needing any passthrough, just using event handling on the wrapper instead of the table headers.

    Could you please explain what you mean by 'true' passthrough; and how absolute positioning affects such a thing? I'm most curious about the intricacies of event-handlers and overlaid sibling elements.


    [1] http://datatables.net/forums/comments.php?DiscussionID=764 (glad you found it!)
  • allanallan Posts: 61,795Questions: 1Answers: 10,115 Site admin
    Hi jnthnlstr,

    Okay - got it now - thanks for the explanation.

    What I had meant by 'true' passthrough is that, when you have an element which is absolutely positioned, it pulls it out of the document flow, so you don't get the normal 'propagation / bubbling' effect that you would expect from nested elements where the children and parents both have events assigned to them. For this reason, you could have an absolutely positioned element (ie. the fixed header) over-laying a relative element (ie. the normal header) and a click on the absolute element wouldn't propagate to the relative element, even although visually they overlap. Hence why I put in the 'passthrough' method I used for 'click'.

    Hope that all makes sense :-)

    Regards,
    Allan
  • visvis Posts: 4Questions: 0Answers: 0
    edited October 2009
    Hi Allan,

    While using it with JavaScript array we had problem with width detection since the table was wider on some pages and narrower in some (we have really wide tables). The width of the columns was not always best but we managed to fix it by setting the table width (you don't have this problem when you "convert" table into DataTable :)

    At the end we added a new function:
    [code]
    this._fnFixWidth = function() {
    if (typeof (_oSettings.nTable) !== 'undefined' && _oSettings.nTable.clientWidth != 'auto')
    _nCTable.style.width = _oSettings.nTable.clientWidth + 'px';

    /* Copy the widths across - apparently a clone isn't good enough for this */
    $("thead:eq(0)>tr th", _oSettings.nTable).each(function(i) {
    $("thead:eq(0)>tr th:eq(" + i + ")", _nCTable).width($(this).width());
    });
    }
    [/code]

    It fixes width of the table and then it goes to all the columns to fix their width. It's almost perfect now :) we placed it into fnDrawCallback and it works really good. You need to call it the first time also. :)

    We also had some problems with filtering columns (we wanted to have them in fixed header as well as sorting and everything else). We fixed them by placing your example code from DataTable into _fnCloneThead. The only problem left was that when you sorted the data it would lost values from cloned table so we placed this into
    $("thead input").keyup(function() (which is now also in FixedHeader.js).

    [code]
    $("thead input").keyup(function() {
    // Filter on the column (the index) of this element */
    _oTable.fnFilter(this.value, $("thead input").index(this));
    var a = $("thead:eq(0)>tr td", _oSettings.nTable);
    if (this.value != '') {
    a[$("thead input").index(this)].childNodes[0].value = this.value;
    a[$("thead input").index(this)].childNodes[0].className = this.className;
    } else {
    a[$("thead input").index(this)].childNodes[0].value = "Trazi u stupcu";
    a[$("thead input").index(this)].childNodes[0].className = "search_init";
    }
    });
    [/code]

    Maybe this can help someone that would also like to include just about everything there is. :)

    Thank you Allan for such a great software!
    S&V
  • allanallan Posts: 61,795Questions: 1Answers: 10,115 Site admin
    Hi vis,

    Nice one! Thanks very much indeed for posting your code. I'm sure that this will prove useful - particularly the fixed header addition - for others in future.

    Regards,
    Allan
This discussion has been closed.