Separate URL for each Vaadin-Tab

Hi,
Vaadin newcomer here. (Vaadin 13)

I’m using Vaadin Tabs and need each tab to have a separate URL, so the user can bookmark the page with the currently selected tab. Is this possible?

I’ve played around with HasUrlParameter and it’s possible to select a specific tab based on the parameter, but of course the URL isn’t changing when changing the tab. Can i change the URL manually? Or is there another approach?

Hi,

have a look at the “RouterLayout” interface.

You probably should place your Tabs in a class which implements the “RouterLayout”. After that, make sure that when clicking a Tab, a navigation occures to a class which is annotation like : “@Route(value = “YourRouteValue”, layout = “YourRouterLayout”.class)”

=)

Hi Magnus

Yes you can change the page title dynamically (for example on tab-change), by letting the view extend HasDynamicTitle.
See [here]
(https://vaadin.com/docs/v10/flow/routing/tutorial-routing-page-titles.html) for the documentation.

Thanks for the help. The RouterLayout is working great :slight_smile:

One last problem: How can i select the associated tab, when i open a view via URL?

I’ve found one solution, but it seems to be very complicated:

  • My view implements BeforeEnterObserver.
  • On beforeEnter i’m reading the new location from the event.
  • I’ve created a mapping from each Tab to its url (via ui.getRouter().getRegistry().getTargetUrl(contentClass of the Tab))
  • With this mapping i can select the corresponding Tab in beforeEnter.
  • My TabSelectionChangeListener has to check, if the event is from the server. If yes don’t trigger the navigation.

Is there a better way?

What do you want to achieve? Because I’m not getting it, sorry.

I am actually trying to do this right now, so I think I know exactly what Magnus means.

let’s assume we have following classes:

  • a MainView (RouterLayout) which contains a tabs with two tab items
  • two Views, one for each tab item. lets call them ViewA and ViewB

Now when opening ViewB (directly via URL, not via tab item click), the tabs from the MainView is displayed, but the tab-item for ViewA is selected because it’s the first tab item. So the second tab item needs to be selected programmatically in this case.

He is doing this by implementing BeforeEnterObserver in the MainView, reading the url and selecting the corresponding tab item.

In my opinion, it would be so much better if this whole logic can be started in the actual child view. But the child view ViewB has no way of knowing the MainView, does it? (please do correct me here if I’m wrong!)
I was trying out (MainView) this.getParent().get() within the ViewB but it doesn’t seem to work.

So to answer Magnus’ question from my point of view: If your approach works, then this is already not so bad. There could be a better way of doing this but I have yet to find it.

Hi,

Are you talking about something like this…?

As I switch tabs the URL bar changes.

Movie…
https://gc4.io/images/TabsUrl.mov

S.

Its more about the other way round. When you type in specific URL (like you did at second 35 of your video), how does your tabs element know which tab item to select?

I put the view class as the ID of the tab (Tab.setId) and evaluated both in the beforeEnter event (in main layout).

Yes, I do something similar. I have multiple tabs sharing the same class view, so I have a map of Tabs and the related data for the view.

In the beforeEnter event, I check the parameters in the url and add the tab to the Tabs component. If the tab already exists (i.e. its in the map) then its just setSelected.

S.

Yes, exactly. That was my problem.
My approach is working, but feels a bit complicated. But as it is just some weird private code, i can live with it :slight_smile:

Kaspar Scherrer:
I am actually trying to do this right now, so I think I know exactly what Magnus means.

let’s assume we have following classes:

  • a MainView (RouterLayout) which contains a tabs with two tab items
  • two Views, one for each tab item. lets call them ViewA and ViewB

Now when opening ViewB (directly via URL, not via tab item click), the tabs from the MainView is displayed, but the tab-item for ViewA is selected because it’s the first tab item. So the second tab item needs to be selected programmatically in this case.

He is doing this by implementing BeforeEnterObserver in the MainView, reading the url and selecting the corresponding tab item.

In my opinion, it would be so much better if this whole logic can be started in the actual child view. But the child view ViewB has no way of knowing the MainView, does it? (please do correct me here if I’m wrong!)
I was trying out (MainView) this.getParent().get() within the ViewB but it doesn’t seem to work.

So to answer Magnus’ question from my point of view: If your approach works, then this is already not so bad. There could be a better way of doing this but I have yet to find it.

I guess, if you’re using Spring, you could define a bean with Request scope that can hold your MainView instance for the current request. In the constructor of MainView, it could pass ‘this’ to this bean. Then in the constructors of ViewA and ViewB you inject this bean and can access the MainView. At least if that was constructed first, I’m not sure that’s necessarily the case. If not, it can be accessed in afterNavigation if the views implement AfterNavigationObserver.

Actually, since the MainLayout knows the classes of the views (in order to navigate on tab selection) it can implement AfterNavigationObserver and look at the first element of the active chain after navigation. It should be an instance of one of those classes corresponding to the selected tab. You can use a subclass of Tab which holds a reference to this class object, for easy lookup.

Hi all,

I have not yet spent time to confirm this in ver 13 but in ver 16, if you are using AppLayout, when wrapping RouterLink inside Tab

Tab tab = new Tab(new RouterLink(myLabel, view.getClass()));

all we have to do is handling ui in showRouterLayoutContent (include tab selection)

@Override
	public void showRouterLayoutContent(HasElement content) {
		super.showRouterLayoutContent(content);
		tabManager.setSelectedIndex(findIndexOfTab(content));
	}

The rest is already handled, so no additional tab selectedChangeListener or beforeEnter, beforeLeave event need.

Hope this will help any newbie like me in the future.

Best,
Tam Nguyen Minh

There’s an example of this in the Vaadin Cookbook that might be helpful: https://cookbook.vaadin.com/tabs-with-routes/a