Docs

Documentation versions (currently viewingVaadin 24)

Navigator in Flow with MPR

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.

The first way is to use 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.

The second is using the Navigator without mixing with Flow. It’s suitable for projects with complex custom navigators.

Last, using only the Flow’s Router 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 by the Flow’s Router.

Mixing Navigation & 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);
  }
}

You 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 example, you 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’s used on all Routes that have it as the parent layout. All you need to do is create a Flow component (e.g., 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 you 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 {
}

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, navigate to a corresponding Flow view, if available. Navigation from a Flow route to a legacy View also works through the Navigator.

By default the MprNavigatorRoute creates a <div> on the client-side, but this can be changed by annotating the subclass with @Tag.

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 Flow Mixing

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 the following:

@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> {
}

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.

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.

The next step is Configuring UI Parameters.

466CAFAE-0226-445A-9863-7665DAB99305