BrowserWindowResizeListener issue

I’m trying to get the screen width by implementing BrowserWindowResizeListener and here is the override method used

    @Override
    public void browserWindowResized(BrowserWindowResizeEvent browserWindowResizeEvent) {
        boolean mobile = UIUtils.isMobile(browserWindowResizeEvent.getWidth());
        log.info("This is mobile ? {}",mobile);

        listing.showMobileColumn(mobile);
    }

It is getting executed only once not when ever changing the viewport size. Am I implementing incorrectly ? What am I missing here ?

I’m not sure about this interface or UiUtils. You have an example here of how to show/hide columns based on the width of the window: How do I make a responsive Grid that has a different set of columns depending on the browser width. - Vaadin Cookbook

1 Like

Had to give the example a bit of make up (getting rid of those horrible optionals): Simplified exampl · vaadin/cookbook@0d5a32a · GitHub

Looks like the resizer is still called without any kind of throttling :thinking:

Yes, it has no throttling, we love our self inflicted DDOS :face_with_hand_over_mouth:

Eh… Let’s fix it. Somehow.

Would something like this work :thinking: Would be also bit more flexible than the original API. Would work (not tested though) for example directly on Grid, if e.g. using in SplitLayout or similar.

I tested this and is providing the dimension details. How can I use this globally ? I mean instead of calling this ResizeObserver on every view, is there a way to set this value once and then just get the value when needed ? I tried this

ResizeObserverView.ResizeObserver.of(UI.getCurrent()).addResizeListener(sizeDetails -> { this.mobile = sizeDetails.width() <=478; });. And this variable is retrieved like this
public boolean isMobile() { return this.mobile; }. but the problem it is not setting the value on every resize on every page view.

There is probably a lot to do for API ergonomics still. I guess this in your code refers to some component/rougte, and once they change, the mobile flag is lost as well. Are you on Spring or CDI? UI scoped bean would probably be quite nice: re-used if moving from view to view, but still easily injectable whenever/whereever you need the detail :thinking:

I’m using spring. I thought I can have this in the MainLayout and then from it, I can get it anywhere/anytime

That should work yes :+1:

In MainLayout I can see the values are getting correctly

2024-04-04 12:10:07,208 INFO [http-nio-8080-exec-9] c.e.application.views.MainLayout.checkDeviceType 457 - This is a mobile device ? true 2024-04-04 12:10:27,512 INFO [http-nio-8080-exec-8] c.e.application.views.MainLayout.checkDeviceType 465 - This is a desktop device ? true 2024-04-04 12:10:43,855 INFO [http-nio-8080-exec-7] c.e.application.views.MainLayout.checkDeviceType 457 - This is a mobile device ? true

But the same value is not getting propagated to the child view

public static boolean isMobile() { return isMobile; }

The child view has this `` boolean mobile = MainLayout.isMobile();
if (mobile) {
log.info(“This is mobile ? {}”,mobile);

        listing.showMobileColumn(mobile);
    }``

Something I still miss in passing the value from MainLayout to ChildView ?

Method of instances can’t be static.

How about this approach ?

public static MainLayout get() { return (MainLayout) UI.getCurrent().getChildren() .filter(component -> component.getClass() == MainLayout.class) .findFirst().get();
In child view I’ve this
``boolean mobile = MainLayout.get().isMobile();
if (mobile) {
log.info(“This is mobile ? {}”,mobile);

        listing.showMobileColumn(mobile);
    }

``. But this is also not working

Öhm… If you only care about mobile and non-mobile… why aren’t you simple asking the WebBrowser class?

I need this working on multiple devices like iPad, iPad pro, mobile phones of different screensize and desktops as well

I had a “passanger seat day” and my plan was to create an example for you how I’d use it, but instead I ended up opening the problematic core feature, which escalated. Knoobie, you can make your review for this and the related PR :nerd_face:

1 Like

Do not mix the two different things. Getting the initial width vs. width change:

        // Add browser window listener to observe width change
        getUI().ifPresent(ui -> browserListener = ui.getPage()
                .addBrowserWindowResizeListener(event -> {
                    adjustVisibleGridColumns(event.getWidth());
                }));

        // Adjust Grid according to initial width of the screen
        getUI().ifPresent(
                ui -> ui.getPage().retrieveExtendedClientDetails(receiver -> {
                    int browserWidth = receiver.getBodyClientWidth();
                    adjustVisibleGridColumns(browserWidth);
                }));

You can see fully functioning demo here: How do I make a responsive Grid that has a different set of columns depending on the browser width. - Vaadin Cookbook

I’m calling this in every view. Is there a way to set this in MainLayout and get this directly from there ?

If you want to react to the size changes (orientation change or browser window resize, not caring just about initial size), you have to re-adjust everything from the listener.

BTW. I refactore that example utility I referred earlier couple of times. I’m getting pretty happy with it now. It doesn’t require that ugly repeating present in the cookbook example, you can get the actual size for components and the size change comes even if it comes from a component like SplitLayout. This example now also shows how to for example configure columns according to the available space:

Once I have the first aid in related to current resize event, I’ll start advocating for this enhancement.

This is definitely going to make mobile programming far easy