JBoss.orgCommunity Documentation

Chapter 11. Errai UI Navigation

11.1. Getting Started
11.2. How it Works
11.2.1. Declaring a Page
11.2.2. Page Lifecycle
11.2.3. Page State Parameters
11.2.4. Declaring a Link with TransitionAnchor
11.2.5. Declaring a Manual Link
11.2.6. Following a Manual Link
11.2.7. Declaring a Link By UniquePageRole
11.2.8. Installing the Navigation Panel into the User Interface
11.2.9. Overriding the default Nagivating Panel type
11.2.10. Handling Navigation Errors
11.2.11. Viewing the Generated Navigation Graph

Starting in version 2.1, Errai offers a system for creating applications that have multiple bookmarkable pages. This navigation system has the following features:

Plugin Tip

Use the Errai Forge Addon Add Errai Features command and select Errai Navigation to follow along with this section.

Manual Setup

Checkout the Manual Setup Section for instructions on how to manually add Errai Navigation to your project.

Errai Navigation has these main parts:

The Navigation singleton owns a GWT Panel called the navigation panel . This panel always contains a widget corresponding to the the fragment ID (the part after the # symbol) in the browser’s location bar. Whenever the fragment ID changes for any reason (for example, because the user pressed the back button, navigated to a bookmarked URL, or simply typed a fragment ID by hand), the widget in the navigation panel is replaced by the widget associated with that fragment ID. Likewise, when the application asks the navigation system to follow a link, the fragment ID in the browser’s location bar is updated to reflect the new current page.

To declare a page, annotate any subclass of Widget with the @Page annotation:

@Page

public class ItemListPage extends Composite {
  // Anything goes...
}

By default, the name of a page is the simple name of the class that declares it. In the above example, the ItemListPage will fill the navigation panel whenever the browser’s location bar ends with #ItemListPage. If you prefer a different page name, use the @Page annotation’s path attribute:

@Page(path="items")

public class ItemListPage extends Composite {
  // Anything goes...
}

There are four annotations related to page lifecycle events: @PageShowing, @PageShown, @PageHiding, and @PageHidden. These annotations designate methods so a page widget can be notified when it is displayed or hidden:

@Page

public class ItemPage extends VerticalPanel {
  @PageShowing
  private void preparePage() {
  }
  @PageHiding
  private void unpreparePage() {
  }
  // Anything goes...
}

A page widget will often represent a view on on instance of a class of things. For example, there might be an ItemPage that displays a particular item available at a store. In cases like this, it’s important that the bookmarkable navigation URL includes not only the name of the page but also an identifier for the particular item being displayed.

This is where page state parameters come in. Consider the following page widget:

@Page

public class ItemPage extends VerticalPanel {
  @PageState
  private int itemId;
  // Anything goes...
}

This page would be reachable at a URL like http://www.company.com/store/#ItemPage;itemId=4. Before the page was displayed, the Errai UI Navigation framework would write the int value 4 into the itemId field.

There are three ways to pass state information to a page: by passing a Multimap to TransitionTo.go() ; by passing a Multimap to Navigation.goTo() , or by including the state information in the fragment identifier of a hyperlink as illustrated in the previous paragraph (use the HistoryToken class to construct such a fragment ID properly.)

A page widget can have any number of @PageState fields. The fields can be of any primitive or boxed primitive type (except char or Character ), String, or a Collection, List, or Set of the allowable scalar types. Nested collections are not supported.

@PageState fields can be private, protected, default access, or public. They are always updated by direct field access; never via a setter method. The updates occur just before the @PageShowing method is invoked.

In addition to receiving page state information via direct writes to @PageState fields, you can also receive the whole Multimap in the @PageShowing and @PageShown methods through a parameter of type HistoryToken . Whether or not a lifecycle method has such a parameter, the @PageState fields will still be written as usual.

Page state values are represented in the URL much like HTML form parameters: as key=value pairs separated by the ampersand ( & ) character. Multi-valued page state fields are represented by repeated occurrences of the same key. If a key corresponding to a @PageState field is absent from the state information passed to the page, the framework writes a default value: null for scalar Object fields, the JVM default (0 or false) for primitives, and an empty collection for collection-valued fields. To construct and parse state tokens programmatically, use the HistoryToken class.

Beginning in version 2.4, Errai will automatically attach the Navigation Panel to the Root Panel, but it is possible to override this behaviour by simply adding the Navigation Panel to another component manually. The best time to do this is during application startup, for example in the @PostConstruct method of your @EntryPoint class. By using the default behaviour you can allow Errai Navigation to control the full contents of the page, or you can opt to keep some parts of the page (headers, footers, and sidebars, for example) away from Errai Navigation by choosing an alternate location for the Navigation Panel.

The following example reserves space for header and footer content that is not affected by the navigation system:

@EntryPoint

public class Bootstrap {
  @Inject
  private Navigation navigation;
  @PostConstruct
  public void clientMain() {
    VerticalPanel vp = new VerticalPanel();
    vp.add(new HeaderWidget());
    vp.add(navigation.getContentPanel());
    vp.add(new FooterWidget());
    RootPanel.get().add(vp);
  }
}

This last example demonstrates a simple approach to defining the page structure with an Errai UI template. The final product is identical to the above example, but in this case the overall page structure is declared in an HTML template rather than being defined programmatically in procedural logic:

@Templated

@EntryPoint
public class OverallPageStrucutre extends Composite {
  @Inject
  private Navigation navigation;
  @Inject @DataField
  private HeaderWidget header;
  @Inject @DataField
  private SimplePanel content;
  @Inject @DataField
  private FooterWidget footer;
  @PostConstruct
  public void clientMain() {
    // give over the contents of this.content to the navigation panel
    content.add(navigation.getContentPanel());
    // add this whole templated widget to the root panel
    RootPanel.get().add(this);
  }
}