Navigation in Flow 14 AppLayout

I don’t quite get navigation in the new AppLayout. In Flow 13 I would add a MenuItem associated with a route-name, and voila, I’d have navigation from the nav-bar/tab-bar to components annotated with the corresponding routes:

...
AppLayoutMenu menu = createMenu();

    @PostConstruct
    public void init() {
        menu.addMenuItems(
                new AppLayoutMenuItem(VaadinIcon.USER.create(), "My Profile", "profile"),
                new AppLayoutMenuItem(VaadinIcon.TRENDING_UP.create(), "Trending Topics", "trends"),
...

In version 14, routing via url works as it should. But looking at the demo-snippets in https://github.com/vaadin/vaadin-app-layout-flow/ I don’t quite understand how to get the navigation items to actually navigate:

@Viewport("width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes, viewport-fit=cover")
@PWA(name = "My Application", shortName = "My App")
class MainAppView extends AppLayout {

    public MainAppView() {
        Image img = new Image("https://i.imgur.com/GPpnszs.png", "Vaadin Logo");
        img.setHeight("44px");
        addToNavbar(new DrawerToggle(), img);
        Tabs tabs = new Tabs(new Tab("Home"), new Tab("About"));
        tabs.setOrientation(Tabs.Orientation.VERTICAL);
        addToDrawer(tabs);
    }
}

I get nice items in the drawer or in the navbar if the tabs are added there, but they’re not bound to any route, how do I do that?

This is surely not how to do it, but it kind-of illustrates what I want (except route and label shouldn’t have to be equal, ofcourse):

        tabs.addSelectedChangeListener(l -> UI.getCurrent().navigate(tabs.getSelectedTab().getLabel()));

As you noticed with AppLayout 2 the menu implementation was removed from the component, previous implementation was very opinionated and specific for using menu in the Navigation Bar, now with the new Drawer slot it’s also possible to build a menu there.

One option is using vertical tabs as it’s mentioned in the snippet. We will re-check the demo snippets so that routing is clear.

In the meantime you can take a look at [App Layout 2 migration guide in docs site]
(https://vaadin.com/docs/v14/flow/v14-migration/app-layout-v2-migration-guide.html#menu)

RouterLink link = new RouterLink(null,TargetView.class);
link.add(VaadinIcon.ARROW_RIGHT.create());
link.add("link text");
Tab tab = new Tab();
tab.add(link);
tabs.add(tab);

Thanks for the pointer to the migration guide, didn’t find that by myself :slight_smile:

Edit: Using RouterLink works like a charm. It’s hard to hit the sweet spot when it comes to opinionated-ness (because there are so many opinions about that … sigh …), but I think you are closer to it now :slight_smile: Demo’ing usage of RouterLink in the demo-snippets would be a good thing, I think.

While I am at it … when navigating by url and address field, instead of clicking RouterLink in the Tabs, I need to set the tab/view navigated to as selected, because it doesn’t keep track on its own. What would be the best way to do that?

.

I came up with this, but it’s not pretty … is there any more elegant way to set the navigation Tab as selected, when navigating using the address field, and not clicking on the RouterLink in the Tab?

    @Override
    public void showRouterLayoutContent(HasElement withElement) {
        super.showRouterLayoutContent(withElement);
            tabs.getChildren().forEach(
                    t -> {
                        if (((RouterLink)t.getChildren().findFirst().get()).getHref().equals(RouteConfiguration.forRegistry(
                                UI.getCurrent().getRouter().getRegistry()).getUrl(((Component)withElement).getClass()))) {
                            tabs.setSelectedTab( (Tab) t);
                        }
                    }
            );
    }

(Not using the drawer in my app, the navigation tabs are added with the addToNavbar-method.)

I need to set the tab/view navigated to as selected, because it doesn’t keep track on its own. What would be the best way to do that?

AfterNavigationObserver would be the one to use; see https://vaadin.com/docs/v13/flow/routing/tutorial-routing-lifecycle.html

Thanks, I made a small class NavTab to handle this:

    static class NavTab extends Tab implements AfterNavigationObserver {

        public final RouterLink link;

        public NavTab(String text, Class<? extends Component> navigationTarget) {
            link = new RouterLink(null, navigationTarget);
            link.add(VaadinIcon.ARROW_RIGHT.create());
            link.add(text);
            this.add(link);
        }

        @Override
        public void afterNavigation(AfterNavigationEvent event) {
            if (event.getLocation().getFirstSegment().equals(link.getHref()))
                ((Tabs)this.getParent().get()).setSelectedTab(this);

        }
    }

OK, now for the next question. Or is it a bug? It’s certainly weird …

When I run the app on my phone (Galaxy 9+ Chrome), the navbar is shown at the bottom of the screen as it should. And when I add more tabs than can be shown, the Tabs component will act as a scroll-band, so that I can swipe left and right to get to the right tab. But, it doesn’t work flawlessly, under some circumstances the scrollband-effect “goes away”, eg. there are no left-right-scroll-arrows, not all tabs are visible, and there is no scrolling either.

Here is some code, I’ve added some extra x’es to consume space. Tabs-scrolling works as it should, except I can’t scroll to the rightmost tab:

        navbarTabs = new Tabs(
                  new NavTab("Flight xxxx", FlightView.class)
                , new NavTab("Trends xxxx",  TrendsView.class)
                , new NavTab("Profile xxxx",  ProfileView.class)
                , new NavTab("Other xxxx",  OtherView.class)
                , new NavTab("Store xxxx",  StoreView.class)
        );

But, what happens when i change the text? If I fill inn the blanks on all tabs, like below, the whole scroll-band-effect goes away.

				new NavTab("Flightxxxxx", FlightView.class)

Is there some space/width calculation going on using word-count for something, that breaks when there turn up longer-than-average strings in the text (blank is replaced by “x”)?

The same problem occurs if all the xxx’es are removed alltogether, no more scrollband-effect. Mavbe because the texts get shorter than some assumed average length in some calculation?

Sounds like a bug. If you can create a simple set of reproduction instructions, you should file a ticket here: https://github.com/vaadin/vaadin-tabs-flow/issues

Can you try setting size to navbarTabs with navbarTabs.setSizeFull();?

I’ll file a ticket. Here is a simple demo:

package com.martinsolaas.spring;

import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.applayout.DrawerToggle;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.spring.annotation.UIScope;

import javax.annotation.PostConstruct;

@UIScope
public class SimpleMainView extends AppLayout {

    Tabs navbarTabs;

    @PostConstruct
    public void init() {

        Image img = new Image("https://i.imgur.com/GPpnszs.png", "Vaadin Logo");

        img.setHeight("44px");
        addToNavbar(true, new DrawerToggle(), img);

        navbarTabs = new Tabs(
                new Tab("Flight xxxx")
                , new Tab("Trends xxxx")
                , new Tab("Profile xxxx")
                , new Tab("Other xxxx")
                , new Tab("Store xxxx")
        );


        navbarTabs.setOrientation(Tabs.Orientation.HORIZONTAL);
        navbarTabs.setSizeFull();

        addToNavbar(true, navbarTabs);
        this.setPrimarySection(Section.NAVBAR);
    }
}
package com.martinsolaas.navbardemo;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.spring.annotation.SpringComponent;
import com.vaadin.flow.spring.annotation.UIScope;

import javax.annotation.PostConstruct;

import static com.martinsolaas.navbardemo.SimpleView.ROUTE;

@UIScope
@Route(value = ROUTE, layout = com.martinsolaas.spring.SimpleMainView.class)
@SpringComponent
public class SimpleView extends VerticalLayout {

    public final static String ROUTE = "simple";

    @PostConstruct
    public void init() {
        add(new Button("Simple"));
    }
}

Here is how it looks in landscape mode (Chrome Galaxy 9+), all navigation tabs visible.

Here is how it looks in “portrait” mode, with navbar scrolled max to the right you can’t see or get at the “Store”-tab.

With Firefox there is no scrolling available at all.

My bad navbarTabs.setSizeFull(); would only work if it’s the only element in the navbar. Will check the example tomorrow and try to clarify and answer in the issue.
Thanks for reporting it!

Just tested rc5, same behaviour.

Same in rc7 as well, BUT the tab-band-scrolling seems to to work with Material theme, all tabs are reachable. (Didn’t test Material with earlier release candidates)

If anybody still face this issue it may worth to look on width attribute of the <vaadin-tabs> tag. By default it is set to 100% and I was able to fix the issue setting width: 100vw.