Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vaadin 8 Grid scrollbars behave erratically when CSS is used for column widths

I have a Grid in my Vaadin 8 application and sometimes the Grid's scrollbars appear when they aren't needed or disappear when they shouldn't. They can even get stuck in a loop. My Grid has five columns, and I only use built-in Renderers that come with Vaadin 8.

I use CSS to set the column width for the first column to 30%. The problem doesn't appear if I remove that line from my theme, but I need it. How can I get it to work?

like image 811
Anna Koskinen Avatar asked May 10 '21 16:05

Anna Koskinen


2 Answers

Vaadin 8 Grid doesn't support configuring column widths via CSS, you should set any and all column width configurations programmatically (via myColumn.setWidth(pixelWidth);) or the client-side calculations break. Those calculations are crucial for determining the expected width for any columns that don't have a fixed width, and are consequently tightly tied into the scrollbar logic.

Unfortunately there is no built-in solution for setting a percentual width for a column, or for getting Grid's actual size from the server side, or for listening to Grid's size change. However, you can use SizeReporter add-on to help with the latter two (check the Code Samples tab for usage instructions), and calculate the required pixel width from there. GridScrollerExtension add-on also offers both functionalities, as well as querying the current column widths and other Grid-specific features.

For a slightly hackier solution you could also use a JavaScript callback to query the width:

        ui.getPage().getJavaScript().addFunction("gridSizeCallback",
                new JavaScriptFunction() {
                    @Override
                    public void call(JsonArray arguments) {
                        // set myColumn width as 30%
                        myColumn.setWidth(arguments.getNumber(0) * 0.30);
                    }
                });
        ui.getPage().getJavaScript()
                .execute("gridSizeCallback(document.getElementById('"
                        + grid.getId() + "').clientWidth);");

Note that this only gives you the initial width, and doesn't help with the resize problem. The solution for that depends on what all can trigger the Grid resize (e.g. repeating the second JavaScript call through ui.getPage().addBrowserWindowResizeListener when the browser is resized).

like image 170
Anna Koskinen Avatar answered Sep 20 '22 07:09

Anna Koskinen


I wanted to extend the answer https://stackoverflow.com/a/67474239/1184842 of Anna Koskinen, but it's a little bit to much code for a comment, so no real separate answer here...

The SizeReporter can be used only as an idea how to send the client side sizes to the server, because one needs the inner width of the tableWrapper in the Escalator of the Grid. Otherwise the vertical scrollbar space might be used as space for the columns leading to wrong results and e.g. wrapping of columns.

I got this working by changing the implementation in an derived class of the Grid with an extended Connector. I changed the init method templating from the extend method from SizeReporterConnector this way:

    @Override
    protected void init() {
        super.init();

        this.extendedGridServerRpc = this.getRpcProxy(ExtendedGridServerRpc.class);

        final Element widget = getWidget().getEscalator().getTableWrapper();

        if (widget.getOffsetWidth() > 0 && widget.getOffsetHeight() > 0) {
            extendedGridServerRpc.innerSizeChanged(widget.getOffsetWidth(), widget.getOffsetHeight());
        }

        LayoutManager.get(this.getConnection()).addElementResizeListener(widget, new ElementResizeListener() {
            public void onElementResize(ElementResizeEvent event) {
                extendedGridServerRpc.innerSizeChanged(widget.getOffsetWidth(), widget.getOffsetHeight());
            }
        });
    }
like image 28
jan Avatar answered Sep 19 '22 07:09

jan