ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 01.01.2026
Просмотров: 2649
Скачиваний: 0
Advanced Web Application Topics
most cases of navigation. Views managed by the navigator automatically get a distinct URI fragment, which can be used to be able to bookmark the views and their states and to go back and forward in the browser history.
11.9.1. Setting Up for Navigation
The Navigator class manages a collection of views that implement the View interface.The views can be either registered beforehand or acquired from a view provider.When registering, the views must have a name identifier and be added to a navigator with addView().You can register new views at any point. Once registered, you can navigate to them with navigateTo().
Navigator manages navigation in a component container, which can be either a
ComponentContainer (most layouts) or a SingleComponentContainer (UI, Panel, or
Window). The component container is managed through a ViewDisplay. Two view displays are defined: ComponentContainerViewDisplay and SingleComponentContainerViewDisplay, for the respective component container types. Normally, you can let the navigator create the view display internally, as we do in the example below, but you can also create it yourself to customize it.
Let us consider the following UI with two views: start and main. Here, we define their names with enums to be typesafe. We manage the navigation with the UI class itself, which is a
SingleComponentContainer.
public class NavigatorUI extends UI { Navigator navigator;
protected static final String MAINVIEW = "main";
@Override
protected void init(VaadinRequest request) { getPage().setTitle("Navigation Example");
//Create a navigator to control the views navigator = new Navigator(this, this);
//Create and register the views navigator.addView("", new StartView()); navigator.addView(MAINVIEW, new MainView());
}
}
The Navigator automatically sets the URI fragment of the application URL. It also registers a URIFragmentChangedListener in the page (see Section 11.10, “URI Fragment and History Management with UriFragmentUtility”) to show the view identified by the URI fragment if entered or navigated to in the browser. This also enables browser navigation history in the application.
View Providers
You can create new views dynamically using a view provider that implements the ViewProvider interface. A provider is registered in Navigator with addProvider().
The ClassBasedViewProvider is a view provider that can dynamically create new instances of a specified view class based on the view name.
The StaticViewProvider returns an existing view instance based on the view name. The addView() in Navigator is actually just a shorthand for creating a static view provider for each registered view.
298 |
Setting Up for Navigation |
Advanced Web Application Topics
View Change Listeners
You can handle view changes also by implementing a ViewChangeListener and adding it to a Navigator.When a view change occurs, a listener receives a ViewChangeEvent object, which has references to the old and the activated view, the name of the activated view, as well as the fragment parameters.
11.9.2. Implementing a View
Views can be any objects that implement the View interface. When the navigateTo() is called for the navigator, or the application is opened with the URI fragment associated with the view, the navigator switches to the view and calls its enter() method.
To continue with the example, consider the following simple start view that just lets the user to navigate to the main view. It only pops up a notification when the user navigates to it and displays the navigation button.
/** A start view for navigating to the main view */
public class StartView extends VerticalLayout implements View { public StartView() {
setSizeFull();
Button button = new Button("Go to Main View", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) { navigator.navigateTo(MAINVIEW);
}
});
addComponent(button);
setComponentAlignment(button, Alignment.MIDDLE_CENTER);
}
@Override
public void enter(ViewChangeEvent event) { Notification.show("Welcome to the Animal Farm");
}
}
You can initialize the view content in the constructor, as was done in the example above, or in the enter() method. The advantage with the latter method is that the view is attached to the view container as well as to the UI at that time, which is not the case in the constructor.
11.9.3. Handling URI Fragment Path
URI fragment part of a URL is the part after a hash # character. Is used for within-UI URLs, because it is the only part of the URL that can be changed with JavaScript from within a page without reloading the page.The URLs with URI fragments can be used for hyperlinking and bookmarking, as well as browser history, just like any other URLs. In addition, an exclamation mark #! after the hash marks that the page is a stateful AJAX page, which can be crawled by search engines. Crawling requires that the application also responds to special URLs to get the searchable content. URI fragments are managed by Page, which provides a low-level API.
URI fragments can be used with Navigator in two ways: for navigating to a view and to a state within a view. The URI fragment accepted by navigateTo() can have the view name at the root, followed by fragment parameters after a slash ("/"). These parameters are passed to the enter() method in the View.
Implementing a View |
299 |
Advanced Web Application Topics
In the following example, we implement within-view navigation.
/** Main view with a menu */
public class MainView extends VerticalLayout implements View { Panel panel;
// Menu navigation button listener
class ButtonListener implements Button.ClickListener {
String menuitem;
public ButtonListener(String menuitem) { this.menuitem = menuitem;
}
@Override
public void buttonClick(ClickEvent event) { // Navigate to a specific state
navigator.navigateTo(MAINVIEW + "/" + menuitem);
}
}
public MainView() { setSizeFull();
//Layout with menu on left and view area on right HorizontalLayout hLayout = new HorizontalLayout(); hLayout.setSizeFull();
//Have a menu on the left side of the screen Panel menu = new Panel("List of Equals"); menu.setHeight("100%");
menu.setWidth(null);
VerticalLayout menuContent = new VerticalLayout(); menuContent.addComponent(new Button("Pig",
new ButtonListener("pig"))); menuContent.addComponent(new Button("Cat",
new ButtonListener("cat"))); menuContent.addComponent(new Button("Dog",
new ButtonListener("dog"))); menuContent.addComponent(new Button("Reindeer",
new ButtonListener("reindeer"))); menuContent.addComponent(new Button("Penguin",
new ButtonListener("penguin"))); menuContent.addComponent(new Button("Sheep",
new ButtonListener("sheep"))); menuContent.setWidth(null); menuContent.setMargin(true); menu.setContent(menuContent); hLayout.addComponent(menu);
//A panel that contains a content area on right panel = new Panel("An Equal"); panel.setSizeFull(); hLayout.addComponent(panel); hLayout.setExpandRatio(panel, 1.0f);
addComponent(hLayout); setExpandRatio(hLayout, 1.0f);
// Allow going back to the start Button logout = new Button("Logout",
new Button.ClickListener() { @Override
public void buttonClick(ClickEvent event) { navigator.navigateTo("");
}
});
300 |
Handling URI Fragment Path |
Advanced Web Application Topics
addComponent(logout);
}
@Override
public void enter(ViewChangeEvent event) { VerticalLayout panelContent = new VerticalLayout(); panelContent.setSizeFull(); panelContent.setMargin(true); panel.setContent(panelContent); // Also clears
if (event.getParameters() == null
|| event.getParameters().isEmpty()) { panelContent.addComponent(
new Label("Nothing to see here, " + "just pass along."));
return;
}
//Display the fragment parameters Label watching = new Label(
"You are currently watching a " + event.getParameters());
watching.setSizeUndefined();
panelContent.addComponent(watching);
panelContent.setComponentAlignment(watching, Alignment.MIDDLE_CENTER);
//Some other content
Embedded pic = new Embedded(null,
new ThemeResource("img/" + event.getParameters() + "-128px.png"));
panelContent.addComponent(pic); panelContent.setExpandRatio(pic, 1.0f); panelContent.setComponentAlignment(pic,
Alignment.MIDDLE_CENTER);
Label back = new Label("And the " + event.getParameters() + " is watching you");
back.setSizeUndefined();
panelContent.addComponent(back);
panelContent.setComponentAlignment(back, Alignment.MIDDLE_CENTER);
}
}
The main view is shown in Figure 11.5, “Navigator Main View”. At this point, the URL would be http://localhost:8080/myapp#!main/reindeer.
Handling URI Fragment Path |
301 |
Advanced Web Application Topics
Figure 11.5. Navigator Main View
11.10. URI Fragment and History Management with UriFragmentUtility
This section is not yet updated for Vaadin 7. The UriFragmentUtility is obsolete in Vaadin 7 and URI fragment changes are handled with a FragmentChangedListener and setFragment() in the Page class, for example: Page.getCurrent().setFragment("foo").
A major issue in AJAX applications is that as they run in a single web page, bookmarking the application URL (or more generally the URI) can only bookmark the application, not an application state. This is a problem for many applications such as product catalogs and forums, in which it would be good to provide links to specific products or messages. Consequently, as browsers remember the browsing history by URI, the history and the Back button do not normally work. The solution is to use the fragment part of the URI, which is separated from the primary part (address + path + optional query parameters) of the URI with the hash (#) character. For example:
http://example.com/path#myfragment
The exact syntax of the fragment part is defined in RFC 3986 (Internet standard STD 66) that defines the URI syntax. A fragment may only contain the regular URI path characters (see the standard) and additionally the slash and the question mark.
The UriFragmentUtility is a special-purpose component that manages the URI fragment; it allows setting the fragment and to handle user-made changes to it. As it is a regular component, though invisible, you must add it to a layout in an application window with the addComponent(), as usual.
302 |
URI Fragment and History Management with UriFragmentUtility |
Advanced Web Application Topics
public void init() {
Window main = new Window("URI Fragment Example"); setMainWindow(main);
// Create the URI fragment utility
final UriFragmentUtility urifu = new UriFragmentUtility(); main.addComponent(urifu);
Notice that the utility component can work only when it is attached to the window, so in practice it must be added in the init() method of the application and must afterwards always remain in the application's user interface.
You can set the URI fragment with the setFragment() method of the UriFragmentUtility object. The method takes the fragment as a string parameter. In the following example, we have a menu, from which the user can select the URI fragment.
// Application state menu
final ListSelect menu = new ListSelect("Select a URI Fragment"); menu.addItem("mercury");
menu.addItem("venus");
menu.addItem("earth");
menu.addItem("mars");
menu.setImmediate(true);
main.addComponent(menu);
// Set the URI Fragment when menu selection changes menu.addListener(new Property.ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
String itemid = (String) event.getProperty().getValue(); urifu.setFragment(itemid);
}
});
The URI fragment and any changes to it are passed to an application as FragmentChangedEvents, which you can handle with a FragmentChangedListener. You can get the new fragment value with the getFragment() method from the URI fragment utility component.
// When the URI fragment is given, use it to set menu selection urifu.addListener(new FragmentChangedListener() {
public void fragmentChanged(FragmentChangedEvent source) { String fragment =
source.getUriFragmentUtility().getFragment(); if (fragment != null)
menu.setValue(fragment);
}
});
Figure 11.6, “Application State Management with URI Fragment Utility” shows an application that allows specifying the menu selection with a URI fragment and correspondingly sets the fragment when the user selects a menu item, as done in the code examples above.
URI Fragment and History Management with UriFragmentUtility |
303 |