Step 3 - Navigation using Navigator in Flow with MPR
Note
| This step is needed in case your Vaadin 7 or 8 application uses Navigator. If it isn’t the case, go back to the framework selection. |
The navigation with MPR can be done in three ways. You can choose the one most suitable for your application, but don’t mix them together. No other approach is supported at the moment and you are on your own if you do it your own way.
-
Using the Navigator together Flow’s Router: this is suitable for creating new views in Flow while maintaining the old views to be routed by the
Navigator
. -
Using the Navigator without mixing with Flow: this is suitable for projects with complex custom navigators.
-
Using only the Flow’s Router: this is suitable for basic navigation setups that can be easily ported, or as the final stage of an incremental porting process.
Note
|
Keep in mind that the old Navigator uses URLs with the "hash-bang" (#! ) prefix. That prefix isn’t used at all by the Flow’s Router.
|
Mixing navigation and Flow routing
It’s possible to use the legacy Navigator and Flow routing together.
Starting from the legacy application:
public class NavigatorUI extends UI {
@Override
protected void init(VaadinRequest request) {
CssLayout viewDisplay = new CssLayout();
Navigator navigator = new Navigator(this, viewDisplay);
navigator.addView("", HomeView.class);
navigator.addView("away", AwayView.class);
VerticalLayout content = new VerticalLayout(viewDisplay);
setContent(content);
}
}
We would make the UI
into a Flow route by extending MprNavigatorRoute
.
@Route("")
public class MyNavigatorRoute extends MprNavigatorRoute {
@Override
public void configureNavigator(Navigator navigator) {
navigator.addView("", HomeView.class);
navigator.addView("away", AwayView.class);
}
}
For a more complex sample we could have a MainMenu
component that’s always visible and used to navigate between the views.
public class MyNavigatorUI extends UI {
@Override
protected void init(VaadinRequest request) {
CssLayout viewDisplay = new CssLayout();
Navigator navigator = new Navigator(this, viewDisplay);
navigator.addView("", HomeView.class);
navigator.addView("away", AwayView.class);
setContent(new VerticalLayout(new MainMenu(), viewDisplay));
}
}
public class MainMenu extends HorizontalLayout {
public MainMenu() {
Button home = new Button("Home",
event -> getUI().getNavigator().navigateTo(""));
Button away = new Button("Away",
event -> getUI().getNavigator().navigateTo("away"));
addComponents(home, away);
}
}
Here we can move the MainMenu
to its own RouterLayout
that is used on all
Routes that have it as the parent layout. All we need to do is to create a Flow
component, such as MainLayout
, that contains the MainMenu
component and add
that to the @Route
annotation.
// Flow router target
@Route(value = "", layout = MainLayout.class)
public class MyNavigatorRoute extends MprNavigatorRoute {
@Override
public void configureNavigator(Navigator navigator) {
navigator.addView("", HomeView.class);
navigator.addView("away", AwayView.class);
}
}
// Flow layout, used by the router
public class MainLayout extends VerticalLayout implements RouterLayout {
public MainLayout() {
add(new LegacyWrapper(new MainMenu()));
}
}
This way we can make a single MainLayout
that can be used both with the old navigator
views as well as with the new Flow views.
To add a Flow view we need to create the route target.
@Route(value = "flow", layout = MainLayout.class)
public class FlowView extends Div {
}
and then add it to the MainMenu
as a Button
.
public class MainMenu extends HorizontalLayout {
public MainMenu() {
Button home = new Button("Home",
event -> getUI().getNavigator().navigateTo(""));
Button away = new Button("Away",
event -> getUI().getNavigator().navigateTo("away"));
Button flow = new Button("Flow",
event -> getUI().getNavigator().navigateTo("flow"));
addComponents(home, away, flow);
}
}
Now the menu can be used to navigate from a legacy view to a Flow view and back.
When requesting the Navigator
to navigate to a view that isn’t registered in
the Navigator
we navigate to a corresponding Flow view if available.
Also navigation from a Flow route to a legacy View works through the Navigator
.
Note
|
By default the MprNavigatorRoute creates a <div> on the client-side, but this can be changed by annotating the subclass with @Tag .
|
Note
|
MainMenu , HomeView and AwayView are legacy Vaadin 7 components and, FlowView and MainLayout are Flow components.
HomeView and AwayView also implement View .
|
Use navigator without mixing with Flow
Navigator can be used as is by having a view display component that is
wrapped in a LegacyWrapper
.
Consider the following simple legacy navigator setup:
public class MyUI extends UI {
@Override
protected void init(VaadinRequest request) {
Navigator navigator = new Navigator(this, this);
navigator.addView("", DefaultView.class);
navigator.addView("subview", SubView.class);
}
}
This would be changed to:
@Route("")
public class Root extends Div {
private final CssLayout content = new CssLayout();
public Root() {
add(new LegacyWrapper(content));
Navigator navigator = new Navigator(UI.getCurrent(), content);
navigator.addView("", DefaultView.class);
navigator.addView("subview", SubView.class);
}
}
Now, navigation to localhost
would show DefaultView
and localhost#!subview
would show SubView
as is expected.
The thing to note in this case is that Flow doesn’t receive any view change events.
Upgrading Views to Flow Routes
Another open path for navigator upgrade is to wrap the existing View
classes
into a MprRouteAdapter<? extends View>
and give the adapter class a Route
.
Then the navigator.addView("away", AwayView.class);
configuration in the previous
example would be changed to:
@Route(value = "away", layout = MainLayout.class)
public class AwayRoute extends MprRouteAdapter<AwayView> {
}
Note
|
By default the MprRouteAdapter creates a <div> on the client-side, but this can be changed by annotating the subclass with @Tag .
|
Now, there is no need to setup a Navigator
and the View still receives a ViewChangeEvent
as it did with the navigator.
Note
|
Any ViewChangeListener should be replaced with a BeforeEnterListener for the beforeViewChange
and an AfterNavigationListener for the afterViewChange to the Flow UI. See Navigation Lifecycle documentation.
|