Binding tabs with a hard URL

If we have an application that works with bigger UI groups, it's nice to separate them with tabs. For example, we want to show different screens for our Contractors, Customers, Employees, and Help pages. The following screenshot shows the initial page of our application. We can see that the Home screen corresponds to the URL.

Binding tabs with a hard URL

And if the user clicks on another tab, the URL has changed.

Binding tabs with a hard URL

How to do it...

Carry out the following steps to create tabs bound with the URL:

  1. Create a project with the main UI class called, for example, Demo.
    public class Demo extends UI {…}
  2. We create a TabsURL class that extends TabSheet.
    public class TabsURL extends TabSheet{…}
  3. Now we create an array of UI group names.
    private static final String tabNames[] =
      {"Home", "Contractors", "Customers", "Employees", "Help"};
  4. We use these names for creating tabs. We insert the createTabs() method into our TabsURL class. Each tab contains a vertical layout with a big label according to the tab's name.
    private void createTabs(String tabNames[]){
      for (String tabName : tabNames) {
        VerticalLayout layout = new VerticalLayout();
        layout.setCaption(tabName);
           layout.addComponent(
              new Label("<h1>" + tabName + "</h1>", ContentMode.HTML));
        layout.setHeight(400, Unit.PIXELS);
        addComponent(layout);
      }
    }
  5. We insert a calling method into the constructor.
    public TabsURL() {
      createTabs(tabNames);
      
    }
  6. We need two mechanisms. The first will change the URL according to the selected tab. The second will select the tab according to the URL. For the first one, we add the SelectedTabChangeListener() listener. In this listener, we get the name of the selected tab. And we use this name for setting the URL fragment. We add the following listener into the TabsURL constructor:
    public TabsURL() {
      createTabs(tabNames);  
      addSelectedTabChangeListener(new SelectedTabChangeListener(){
        @Override
        public void selectedTabChange(SelectedTabChangeEvent event)
        {String selectedTabName =
                     event.getTabSheet().getSelectedTab().getCaption();
           UI.getCurrent().getPage().setUriFragment(selectedTabName);
        }
      });
    }
  7. Next, we need a method that selects the tab according to the URL. We create another selectTab() method in our TabsURL class. It must be public because we will call it from the root class. From the page, we get the URL fragment. If the returned fragment has a null value, it means that no string after the # character in the URL has been set. In that case, we select the first tab. If the fragment has been set, we change it to lower-case, because we don't need a case-sensitive URL now. Then, using the iterator we go through all the tabs in TabSheet and check if the fragment equals the tab's name. If no match is found, we select the first tab.
     public void selectTab(){  
        String fragment= UI.getCurrent().getPage().getUriFragment();
        if (fragment == null) {
          setSelectedTab(0);
          return;
        }
        Iterator<Component> iterator = getComponentIterator();
        while (iterator.hasNext()){
          Component tab = iterator.next();
          String name = tab.getCaption().toLowerCase();
          if (fragment.toLowerCase().equals(name)){
          setSelectedTab(tab);
          return;
        }
      }  
      setSelectedTab(0);
     }
  8. Now let's return to our root class called TabRoot. In the init() method, we create an object of the TabsURL class and set this object as a content of the application. After that we can call the selectTab() method. It ensures that the appropriate tab is selected at the initialization application. For selecting tabs after each changing of the URL, we add FragmentChangedListener().
    @Override
    public void init(WrappedRequest request) {
      final TabsURL tabsURL = new TabsURL();
      setContent(tabsURL);  
      tabsURL.selectTab();  
    
    getPage().addUriFragmentChangedListener(
                                  new UriFragmentChangedListener() { 
        @Override
        public void uriFragmentChanged(
                                    UriFragmentChangedEvent event) {
          tabsURL.selectTab();    
        }
      });       
    }

How it works...

In this example, we write and read browser fragment changes. Fragment is the string after the # character in the URI. Writing is performed by the setFragment(String fragment) method. Reading is performed by FragmentChangedListener that is added to the init() method in the root class. When the user clicks on a tab in the TabSheet layout, the URI fragment is changed according to the selected tab's name. When the URI is changed, a tab is selected according to the fragment string. If the fragment does not match with any tab's name, the first tab is selected.

There's more...

Using the caption as an identifier can cause failures in some circumstances (for example, i18n). In this recipe we used a simple identifier, but when we want to use a complicated identifier we have to convert it to the correct URI fragment.

For example we can use the method that replaces all whitespaces with dash:

private String convertNameToFragment(String name) {
  return name.replaceAll("\\s","-");
}

In our case, we can use it as follows:

  1. Update in the TabsURL() constructor.
    UUI.getCurrent().getPage().setUriFragment(convertNameToFragment(selectedTabName));
  2. Update in the selectTab() method.
    String name = convertNameToFrament(tab.getCaption().toLowerCase());
  3. And also insert some spaces in the tab names.
    tabNames[] = {"Home", "Contractors", "New customers", "Employees", "Quick help"};

See also

  • Vaadin 7 comes with a new set of APIs to aid navigation within our application. The main concepts Navigator and View are described in the following recipe. Other recipes describing the work with the listeners are in Chapter 5, Events.
  • The API of the TabSheet class is available at https://vaadin.com/api/7.0.0/com/vaadin/ui/TabSheet.html.