Scroll Body Height not calculated properly in IE 7.

Scroll Body Height not calculated properly in IE 7.

marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
edited April 2012 in DataTables 1.9
The Problem:
If sScrollY and bScrollCollapse are set, the calculated height of the Scroll Body is not correct in IE <= 8. I started debugging the datatables code and found the following code:
[code]
3291 if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
3292 {
3293 nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
3294 var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
3295 o.oScroll.iBarWidth : 0;
3296 if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
3297 {
3298 nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
3299 }
3300 }
[/code]

$(o.nTable).height() is a different value than o.nTable.offsetHeight. You are using o.nTable.offsetHeight (line 3296) for the height comparison to see of a change is needed the height of the scrollbody container. However, when you are defining the height, you use $(o.nTable).height() function. This leads to inconsistency. If one is using one particular calculation for the comparison, then the same calculation needs to be used for the setting. I changed the code to
[code]
3291 if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
3292 {
3293 nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
3294 var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
3295 o.oScroll.iBarWidth : 0;
3296 if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
3297 {
3298 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
3299 }
3300 }
[/code]
and it started working properly in all versions of IE. I tested in FF and Chrome as well. This was tested with DT 1.9 and jQuery 1.7.2.

Also, what is the purpose of the iExtra? It seems to be calculated using "widths", yet it is added to the height. Is this by design? If so, can you explain what it is doing? (p.s. I am not saying it is incorrect, I am just trying to understand the code).

Thanks.

Marc

Replies

  • marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
    So I am digging into this a little deeper and I noticed that widths of the header row are misaligned if I try to apply the height adjustment above in my js outside of the Datatables code as I want to keep the same Datatables versions and the integrity of the code. If I apply the height adjustment after the table is rendered, the height problem is fixed. However, the ScrollHeadTable and ScrollHeadInner elements are not. This is because they are calculated while the "scroll bar" is showing before the fix. This explains why the header widths can be off by a few pixels across the board. To try to correct my specific issue, I am going to readjust the scrollheadinner and scrollheadtable elements in my js as a hotfix.

    Allan,
    I am curious to see what you have to say concerning the code adjustments I made in the previous post. Am I correct in my analysis or am I missing something that might break the integrity of your product? (which, btw, is a great piece of work).

    Thanks.

    Marc
  • marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
    edited April 2012
    Ok, so I found the differences in header widths and the table widths. I have my columns fixed width. The first column is set to 100px in both the TH and TD elements of the table. I also have "aoColumns" defined with 100px as the sWidth for the first column. As the table is being initialized the following code is executed. (p.s. this test was in Chrome).

    [code]
    // around line 3274
    _fnApplyToChildren(function(nSizer, nToSize) {
    oStyle = nSizer.style;
    oStyle.paddingTop = "0";
    oStyle.paddingBottom = "0";
    oStyle.borderTopWidth = "0";
    oStyle.borderBottomWidth = "0";
    oStyle.height = 0;

    iWidth = $(nSizer).width();
    nToSize.style.width = _fnStringToCss(iWidth);
    aApplied.push(iWidth);
    }, anHeadSizers, anHeadToSize);
    [/code]

    Stopping on the first statement in the function and examining everything here are the values in question.

    nSizer.style.width = 100px //correct
    $(nSizer).width() = 98 // not correct -- well to me.
    nSizer.offsetWidth = 110
    $(nSizer).innerWidth = 108
    $(nSizer).outerWidth = 110
    nSizer.clientWidth = 109
    $(nSizer).css("width") = 100px
    document.defaultView.getComputedStyle(nSizer, null).getPropertyValue("width") = 99px // getting closer
    document.defaultView.getComputedStyle(nSizer, null).width = 99px
    $.style(nSizer, "width") = 100px // same as $(nSizer).css("width")
    $.css(nSizer, "width") = 98 // same as $(nSizer).width()

    question, I ask myself "Why would the jQuery width method return 98 when the style is clearly 100px?" I am not familiar enough with the jQuery code based to answer this off the top of my head. So I look at the source code for jQuery and I cannot determine how the value of 98 is returned. I checked the offsetWidth of the nSizer HTML element. Any help here would be appreciated.

    So why is the Header row widths, being recalculated anyway? Does the browser think there is a scrollbar during this calculation and thus the widths return by jQuery's width method is reduced to account for that?

    I finally got it. jQuery's width method returns the offsetWidth minus any padding and (margin or border). I have a border of 1px around each cell and left and right margin of 5px each. Therefore, the offset is 110 - 5 - 5 - 1 - 1 which == 98. This explains why the width is 98. jQuery is going to return the actual physically rendered width of the element not including paddings, margin, borders, etc. With that being said. That explains the difference in the numbers and the resizing. Which leads me full circle. Why readjust the header column widths differently especially if widths are specified by the user?


    Thanks.

    Marc
  • allanallan Posts: 63,695Questions: 1Answers: 10,500 Site admin
    Hi Marc,

    Can I just check which version of DataTables you are using - 1.9.0 or the 1.9.1.dev nightly? There have been a few changes in this area since 1.9.0 which will be released as 1.9.1 soon.

    Your change for using offsetHeight consistently sounds perfectly sensible to me - I'm not sure why I did it the old way before! I've just committed this change and is now in the nightly.

    Regarding the use of iExtra - the reason this is used is to calculate if extra height is needed for the table viewport because we have a horizontal scrollbar (i.e. calculating the widths to see if we need to add height for the horizontal scroll).

    > question, I ask myself "Why would the jQuery width method return 98 when the style is clearly 100px?"

    Yup - your answer to yourself is bob on - the box model is coming into play here. In all honest consistent width for columns in tables is virtually impossible when taking into account the browser differences and the complexity of the column width algorithm used by the browsers.

    > Why readjust the header column widths differently especially if widths are specified by the user?

    Because, they are very likely not to be what is applied in the browser. For example, lets say you have a table with 3 columns and you tell them each to be 100px, and the table itself to be 100% of its parent which happens to have a container width of 800px - what happens? The 100% wins and the 100px for each column is thrown out by the browser. If you do reduce your table to 300px, what happens when content in one cell is >100px? Again the browser tries to adjust for this. There are a load of different factors which make the column widths change, hence why I've found it necessary to apply the widths as I had - the widths you give with sWidth are effectively "best effort".

    Widths for the columns in the scrolling tables are my least favourite bit of DataTables... However, hopefully this will give you some insight into what is going on! Thanks for the stimulating discussion (how to wake up in the morning!).

    Regards,
    Allan
  • marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
    Allan,
    I am definitely using 1.9.0 official release. Can we continue the discussion with the column readjustments? Let me start off by saying, that your explanation was great and suffice. From my review and debugging (I pretty much spent all day yesterday stepping through the code, etc.) I saw where the THs of the THEAD are being recalculated per the code above in this thread. I guess the main problem or question I have is I can't see where the TDs of the main part of the table is being recalculated as well. This is causing a "misalignment" between the "header" row and the "body" rows. I think this is what Frank was referring to in the other thread. I only see this with "fixed-width" tables which I like to use because it gives the users a consistent look and feel when the data varies a lot (which is the case for our internal applications). Should there be code added to apply the width adjustments on the TDs of the body portion to be consistent with the changes to the THs of the head portion?

    Also, so we are clear. I am using bJqueryUI = true, which means there are "two" tables created.

    Thanks.

    Marc
  • marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
    Also, when do you expect the 1.9.1 release?

    Marc
  • allanallan Posts: 63,695Questions: 1Answers: 10,500 Site admin
    > I guess the main problem or question I have is I can't see where the TDs of the main part of the table is being recalculated as well.

    They aren't :-). I think this is related to:

    > I am using bJqueryUI = true, which means there are "two" tables created.

    That's not quite the case actually - its the scrolling features that cause this split, not the jQuery UI theming.

    So the way the column widths work in DataTables is that the _fnCalculateColumnWidths function will attempt to calculate the widths needed for the columns (this is effectively the "master width"). Then in the scroll draw function that you were looking at yesterday, the master widths that were calculated are applied to the header. After that the logic in that scroll draw function attempts to force the columns in the two tables into alignment (there is a hidden 'header' in the tbody table which has the widths applied to it).

    The way that the master widths are calculated can sometimes cause an error - they are done by finding the longer string in each column and assembling a "worst case" table which the browser renders and the widths are read from. However, this can be incorrect since "iiii" take up less with than "mmm", but the i's are longer... This can result in column misalignment. The scroll draw function does try to take this into account by forcing the widths - but as you are seeking that isn't always perfect. If you can link me to your test case what you be very helpful. Also I would suggest trying the 1.9.1 nightly since there are a number of improvements in this area.

    1.9.1 should be out in the next few days :-)

    Allan
  • marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
    Thanks for the clarification about the "scrolling" causing the two tables and not jQUeryUI=true. (I think I actually knew that and got confused).

    If I specify the widths on the TD tags of my table, then I always get misalignment in Chrome, IE, and FF. If I remove the widths from the TD and just specify the width in the aoColumns and/or TH tags it works fine in the three browsers with the exception of older versions of IE. If IE in compatibility mode or IE <= 7, then there is column misalignment. It is only a pixel or two here. I am not sure if you want to spend the time "worrying" about this or not. It is a concern for me as most of our internal users are on IE7 or IE8 (which is probably in compatibility mode), but there is hope for us as we are in the process of upgrading. If you still want my test case, I will be glad to ZIP it up for you and email it to you for your review.

    Thanks.

    Marc
  • allanallan Posts: 63,695Questions: 1Answers: 10,500 Site admin
    If you could drop a self contained demo to me that would be great. My e-mail address is at the top of the DataTables source file :-)

    Allan
  • marcfarrowmarcfarrow Posts: 28Questions: 0Answers: 0
    Thanks for 1.9.1 Allan. This has corrected the issued I had.

    Marc
  • allanallan Posts: 63,695Questions: 1Answers: 10,500 Site admin
    Fantastic - thanks for the feedback :-)

    Allan
  • awvidmerawvidmer Posts: 8Questions: 0Answers: 0
    Hi, Allan:
    I'm having a similar problem with the footer. I had hoped the new release would fix it, but no:

    I'm using Twitter Bootstrap, with bScrollCollapse, sScrollY, and a 305px scroll window set, and everything looks great, except for the footer. Until enough rows are added to the table to create scrolling, the footer appears separated from the scrollBody, due to the apparent calculation of the scrollBody height (it's showing up as an "element.style" in Firebug). Same issue in both Safari and Firefox.

    Since the misalignment is variable, there's no easy way to fix it with css. After reading this thread, I dove into the same code area, but had no luck seeing where the issue is (I thought it might be "iExtra," since I'm using no horizontal scroll, and the separation is about scrollbar height....).

    Even a hack to fix the issue would be appreciated....

    Thanks!

    -- Tony
  • allanallan Posts: 63,695Questions: 1Answers: 10,500 Site admin
    Hi Tony,

    Can you link us to a test case showing the problem please?

    Allan
  • awvidmerawvidmer Posts: 8Questions: 0Answers: 0
    Messaged you directly, Allan. Thanks! -- Tony
  • awvidmerawvidmer Posts: 8Questions: 0Answers: 0
    Finally figured out why the footer was misaligned, Allan: I was using the "header SORT" extension:


    $.extend( $.fn.dataTableExt.oStdClasses, {
    "sSortAsc": "headerSortDown",
    "sSortDesc": "headerSortUp",
    "sSortable": "header"
    } );

    This threw things off. Removed = perfect! Just FYI. Thanks!
This discussion has been closed.