Smoother Vaadin portlet initialisation - fix the height!

Vaadin portlets initialise using JS and XHRs, typically a couple of milliseconds later than basic html markup based portlets. This approach may cause “flickering”, which may be a bit disturbing if there is other content below the Vaadin portlet, because the browser needs to re-flow the whole page after the Vaadin UI has decided how much space it actually needs in vertical direction.

This feeling of slightly sluggish initialisation can be minimised by fixing the height of the portlet. Fixed height will let browsers make some optimisations (no full page reflow), but more essentially the rendering just feels smoother without the visible reflow. Fixing the portlet height also often makes UI design easier as one can use full height in the Vaadin UI code and user relative sizes to position and stretch components.

There are two good ways to fix the height:

  1. Using Liferay’s per portlet styling (or global theme) after the portlet has been installed on some page.
  2. A programmatic approach in your portlet code.

I favor the second one as it gives a good default for your portlet and requires less tricks from the actaul portal maintainer, who might be much less technical people than you are. Let’s see how this is done.

An initial idea for Vaadin developers would be to use your portlets theme to fix the height or call setHeight method for the UI class. The problem with these approaches is that the theme is also injected dynamically by bootstrap code (html+js) and the explicit size comes a bit too late with the initial XHR that contains the state of the UI. Neither would avoid the slight flickering. Instead we’ll use a concept called BootstrapListener to modify the bootstrap code that VaadinPortlet generates.

The BootstrapListener is attached per user, so we’ll use a SessionInitListener and hook that by introducing our own Portlet class:

public class MySpringVaadinPortlet extends SpringAwareVaadinPortlet {
    @Override
    protected void portletInitialized() throws PortletException {
        super.portletInitialized();
        // ... or modify the Vaadin generated bootstrap html/js code
        getService().addSessionInitListener(new SessionInitListener() {
            @Override
            public void sessionInit(SessionInitEvent event) throws ServiceException {
                event.getSession().addBootstrapListener(new BootstrapListener() {
                    // The implementation...
                });
            }
        });
    }
}

As my app uses Spring, I’m extending the SpringAwareVaadinPortlet, but you can extend the raw VaadinPortlet class as well. To actually use the custom portlet, remember to modify the portlet class declaration in your portlet.xml file.

In my example I wrote the BootstrapListener rudely as an inner class to the portlet as follows:

@Override
public void modifyBootstrapPage(BootstrapPageResponse response) {
    // NOP This is used by servlets only
}
@Override
public void modifyBootstrapFragment(BootstrapFragmentResponse response) {
    Element styleElement = 
            Jsoup.parseBodyFragment("").createElement("style");
    String classname = 
            LibraryPortletUI.class.getSimpleName().toLowerCase();
    styleElement.text("."+classname+
            " { height:"+LibraryPortletUI.portletHeight+";}");
    response.getFragmentNodes().add(0, styleElement);
}

To generate (and customize) the bootstrap stuff, Vaadin uses the popular JSOUP library to handle the stuff. Refer to their documentation in case you want to do something fancier. We could, for example, get a similar result by just declaring the height to the first Node like this:

Node n = response.getFragmentNodes().get(0);
n.attr("style",”350px”);

The former approach is a bit more elegant as it just defines a default height to our portlet, which can be easily overridden in the portlet’s own CSS declarations.

I hope your Vaadin portlets are smoother than ever after this pro tip!