Friday, May 4, 2012

FireFox 4 no longer supports scrollable TBody - workarounds?


Well as mentioned in the Firefox 4 changelog , there will be no longer support for scrollable <tbody> 's.



There are a bunch of workarounds - javascript or 2 seperate tables - but none of them solves all problems. Javascript is obviously slower (with 600 rows you can forget to try to scroll a table), and 2 tables are gonna be problematic with cell-width.



Do you know if there is some cool way to do this? We are using jsf / facelets and now have to redo the tags, starting with a good idea would be awesome :-)


Source: Tips4all

6 comments:

  1. I know you're trying to avoid js/separate table implementations, but it was the only one I could find that worked across multiple browsers. Try http://www.tablefixedheader.com/. It's a jquery solution and worked, in my limited testing, across IE6 / IE8 / FF3. (Haven't tested FF4).

    ReplyDelete
  2. PrimeFaces and RichFaces have scrollable datatable components which fetches new rows by ajax.

    (both JSF component libraries uses jQuery under the covers anyway)

    ReplyDelete
  3. Just got slammed with this after I upgraded. Boo.

    I found this in the tubes.

    This code is working in FFX 4. Not in IE8... could be modified.

    http://www.imaputz.com/cssStuff/bigFourVersion.html

    ReplyDelete
  4. Try the first method of this page, pure CSS with a single table (2 divs around the table, and the thead is positionned absolute) : tablescroll
    Seems to work on FF4/IE9/IE8 in addition to IE7/FF3.6.

    ReplyDelete
  5. Thanks to digitaldigs from MozillaZine, I was able to make it work with few modifications.
    The fix works great for FF4, FF7 and FF11.

    I hope this helps! :)

    Issues I have fixed-
    1. scrollWidth did not work for me so had to go for offsetWidth


    Scroll bar width 16 pixel also was not helping so removed it. Instead made my tbody style as-

    .scrollContent {
    overflow-x:hidden;
    overflow-y:scroll; /* I did this only for Mozilla. IE will show 2 scroll bars if applied*/
    display:block;
    }
    With change #2, I had to pad the last cell of the header to accomodate scroll bar.

    /* I did this only for Mozilla. Not for IE*/

    .fixedHeader tr th:last-child {
    padding-right: 20px;
    }
    My fixed header table has colspan used a lot hence was not able to set width, so I first look for a correct row with correct number of cells and then I process.


    My code looks like below:

    function makeMeFixedHeader(){
    var tbodys = document.getElementsByName("scrollTableBody");
    if (tbodys){
    for(var i=0;i<tbodys.length;i++){
    // We can put logic here to check if the current height
    // of tbody has crossed the specified limit or not
    do_tbodyscroll(tbodys[i]);
    }
    }
    }


    function do_tbodyscroll(_tbody){
    // get the table node
    var table = _tbody.parentNode;

    // Get the Last row in Thead ...
    // COLGROUPS USING COLSPAN NOT YET SUPPORTED
    var thead = table.getElementsByTagName("THEAD")[0];
    var _rows = thead.getElementsByTagName("TR");
    var tableheader = _rows[_rows.length - 1];
    var headercells = tableheader.cells;

    // rows of tbody
    var _frows = _tbody.getElementsByTagName("TR");

    // first row of tbody
    var _fr = _tbody.getElementsByTagName("TR")[0];
    //var _fr = _tbody.getElementsByName("scrollTableRow")[0];

    // first row cells ..
    var _frcells = _fr.cells;

    if (_frcells.length < headercells.length){
    var rowCount = 1;
    while (rowCount < _frows.length){
    // nth row of tbody
    _fr = _tbody.getElementsByTagName("TR")[rowCount];
    //var _fr = _tbody.getElementsByName("scrollTableRow")[rowCount];

    // nth row cells ..
    _frcells = _fr.cells;

    if (headercells.length == _frcells.length){
    break;
    }
    rowCount++;
    }
    }

    // Apply width to header ..
    for(var i=0; i<headercells.length; i++){
    if (tableheader.cells[i].offsetWidth != _fr.cells[i].offsetWidth){
    var lastColumn = (i == headercells.length-1)?true:false;
    var changeWidth = (lastColumn)? ((rowCount >= 1)?true:false)
    :true;
    var headerW = tableheader.cells[i].offsetWidth;
    var cellW = _fr.cells[i].offsetWidth;

    if (headerW < cellW){
    tableheader.cells[i].width = cellW;
    _fr.cells[i].width = tableheader.cells[i].width;

    if (lastColumn)
    tableheader.cells[i].width = tableheader.cells[i].offsetWidth-20;

    }else{
    tableheader.cells[i].width = headerW;
    _fr.cells[i].width = tableheader.cells[i].width;

    if (lastColumn)
    _fr.cells[i].width = tableheader.cells[i].offsetWidth-20;
    }
    }
    }

    //var j = headercells.length-1;
    // ADD 16 Pixel of scroll bar to last column ..
    //tableheader.cells[j].width = _fr.cells[j].offsetWidth + 20;

    tableheader.style.display = "block";
    _tbody.style.display = "block";
    }

    ReplyDelete
  6. Why not use a scrollable div? Maybe one of these two options:

    <table>
    <row>
    <cell>
    <div of headers>
    <div of content (scrollable)>
    </cell>
    </row>
    </table>


    or simpler:

    <div of headers>
    <div (scrollable)>
    <table of content, no headers>
    </div>


    Not pretty I know but hey I'm no Michaelangelo :)

    ReplyDelete