0

I'm using two flex tables. One for header and one for data.
The one for data is wrapped with a scroll panel.
The size of my columns is presented with percentage and this is where my problem begins:
I set the width of both tables to 100%.
The thing is that the scrollbar isn't always visible. It's visible only when required.
So when the scrollbar is shown - there's a gap between the width of the header and the width of the data area inside the scrollpanel. (since the scrollbar itself has width of 16px)
This way, the titles of the columns, doesn't match precisely the data columns.

Any suggestions?
Thanks in advance!

user1579191
  • 91
  • 2
  • 10

3 Answers3

0

There are a lot of possible things you can do to keep columns in sync, but most of them requires active layout and/or preview resize events.

I guess that, for your use case, is much simpler and (performance wise) far faster to either:

  • shrink both tables a bit, to always accomodate the space for the scrollbar (or even remove the scrollbars at all, keeping the scrolling behavior functionality). Both solutions are generally achieved by using a pair of nested div, with the second one wider enough to hide/accomodate the scrollbar;
  • wrap your second table into a panel that does not shrink the content when it overflows. In GWT you can do that natively using a CustomScrollPanel (instead a ScrollPanel). Just pay attention that is a RequiresResize panel that needs either an interrupted chain of ProvidesResize containers, or an explict size.

Side note: If you ever need to calculate the size of the native scrollbars in a cross browser solution, just use AbstractNativeScrollbar.getNativeScrollbarHeight() (and/or the width one).

Andrea Boscolo
  • 3,038
  • 1
  • 16
  • 21
  • * Shrinking the header table isn't good for me, since now I have the opposite problem. When the scrollbar doesn't appear - the header is too small for the data table.(now the data table takes all 100% of width and the header not). I don't want to always show the scrollbar, and I didn't find a way to remove the scrollbar. * I didn't understand your second point. Could you explain a little more, or give an example? Thank you! – user1579191 Jul 29 '13 at 04:08
  • I simply meant to use a `CustomScrollPanel` instead of a `ScrollPanel` to wrap the data table. – Andrea Boscolo Jul 29 '13 at 18:28
0

A common trick for this sort of thing that avoids complex code and layout is to simply fix the widths of all your columns except the last one. The last column will auto adjust and you won't have to worry about the scrollbar at all.

Here is a jsfiddle sample along with some sample html/css to show you what I mean. The caveat is that all of the columns have to have width (they cannot be percentages) except the last one.

jsfiddle example

CSS:

.container {
    width: 500px;
    border: 1px solid red;
}

.content-wrapper {
    overflow: auto;
    height: 75px;
}

table {
    width: 100%;
    border-collapse: collapse;
}

col {
    width: 100px;
}

col:last-child {
    width: auto;
}

.container td {
    border: 1px solid green;
}

HTML:

<div class="container">
    <div class="header-wrapper">
        <table class="header">
            <colgroup>
                <col/>
                <col/>
                <col/>
                <col/>
                <col/>
            </colgroup>
            <tr>
                <td>Column A</td>
                <td>Column B</td>
                <td>Column C</td>
                <td>Column D</td>
                <td>Column E</td>
            </tr>
        </table>
    </div>
    <div class="content-wrapper">
        <table class="content">
            <colgroup>
                <col/>
                <col/>
                <col/>
                <col/>
                <col/>
            </colgroup>
            <tr>
                <td>Row 1/A</td>
                <td>Row 1/B</td>
                <td>Row 1/C</td>
                <td>Row 1/D</td>
                <td>Row 1/E</td>
            </tr>
            <tr>
                <td>Row 2/A</td>
                <td>Row 2/B</td>
                <td>Row 2/C</td>
                <td>Row 2/D</td>
                <td>Row 2/E</td>
            </tr>
            <tr>
                <td>Row 3/A</td>
                <td>Row 3/B</td>
                <td>Row 3/C</td>
                <td>Row 3/D</td>
                <td>Row 3/E</td>
            </tr>
            <tr>
                <td>Row 4/A</td>
                <td>Row 4/B</td>
                <td>Row 4/C</td>
                <td>Row 4/D</td>
                <td>Row 4/E</td>
            </tr>
            <tr>
                <td>Row 5/A</td>
                <td>Row 5/B</td>
                <td>Row 5/C</td>
                <td>Row 5/D</td>
                <td>Row 5/E</td>
            </tr>
        </table>
    </div
</div>
xsee
  • 1,173
  • 1
  • 9
  • 12
  • Thanks. I know this trick, the thing is that in my table the last column contains a button, and I want it to be aligned to the left. So I need to give another column size in percentage, so I'm still stuck. – user1579191 Jul 29 '13 at 03:55
  • Ahh, then you are left having to code it. I will post another answer shortly with another technique I use when I have a more complex layout like what you have. Stand by... – xsee Jul 29 '13 at 04:17
0

Based on your comment from my other answer you are left with having to code. I have solved this sort of problem in the past by using a shim column. I wouldn't call it elegant but it did the trick. Basically, you have an extra column in your header at the end that acts as a shim for the scrollbar. When the scrollbar is being displayed then the shim column is displayed with the exact width of the scrollbar. When there is no scrollbar you hide the shim.

  1. Setup your layout with the additional column. Style it however you want. I usually make it so it blends in with the adjoining column so the user doesn't see a little square when it is being displayed.

  2. Add all your data rows to the content table as you normally would. Make sure the content table and all its tr/td are added to the DOM.

  3. Once the data is added then test whether the scrollbar is visible. You can do this by checking if the scroll height is greater then the offset height.

    ScrollPanel scrollPanel;
    Element scrollElem = scrollPanel.getElement();
    
    if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
        // scrollbar is visible
    }
    
  4. If the scrollbar is displayed then show your shim column, otherwise hide it.

    if (scrollElem.getScrollHeight() > scrollElem.getOffsetHeight()) {
        // scrollbar is visible - show shim column
        shimColumnTD.getStyle().setDisplay(Display.BLOCK);
    }
    else {
        // scrollbar not visible - hide shim column
        shimColumnTD.getStyle().setDisplay(Display.NONE);
    }
    
  5. Determine the width of the shim column so that it matches the width of the scrollbar. If you go look inside the below method you can see how it does this.

    // calculate the width of the scrollbar for the given browser
    int shimWidth = AbstractNativeScrollbar.getNativeScrollbarWidth();
    

Obviously, this is just all pseudo but it should lead you in the right direction. Good luck...

xsee
  • 1,173
  • 1
  • 9
  • 12
  • I tried to do what you suggested, but I'm having a problem with point 2: "Make sure the content table and all its tr/td are added to the DOM". I add the data to the flextable and add the table to a dockLayoutPanel which is the widget I pass in initWidget(). But the above check about the scrollbar doesn't work. It always return true. I saw that it first makes the check, and only afterwards refreshes the scrollpanel with the new data. (even though I first enterd the data and afterwards made the check). I guess that's why it doesn't work, but I don't know how to fix it. Thanks for your help! – user1579191 Jul 29 '13 at 07:41
  • Ok, I found the problem. As I said, it checked to see if there's a scrollbar, before it draws the scrollpanel. I solved this by using Scheduler.get().scheduleDeferred(command), and in the command I made the check. This way it first draws the scrollpanel and afterwards makes the check. – user1579191 Jul 29 '13 at 08:43
  • Deferred command was going to be my next suggestion. Glad you got it figured out. – xsee Jul 29 '13 at 14:35