This post is only instructional and is a bit boring as no application is created, but you may take it as simple reference card. Sorry folks!
1. @Route annotation
Here is a simple example of this annotation1 2 3 4 5 6 | @Route("") public class HelloWorld extends Div { public HelloWorld() { setText("Hello world"); } } |
This is shown in the URL http://localhost:8080/myProjectName
Where myProjectName can be used or not depending on the type of deployment (maybe in Jetty is not used but in Tomcat should be used)
@Route ("some/path") references http://localhost:8080/myProjectName/some/path
If the @Route annotation is not present, this criterion is used:
- The route is the class name but decapitalized ("MyClass" -> "myclass")
- The suffix "view" will be trimmed ("PersonView" -> "person")
- The suffix "main" will be trimmed ("MainPerson"-> "person", "MainView"-> "")
2. Events
2.1 Before leaving a page...
Before leaving a page can be detected by means of "BeforeLeaveEvent" only if:
- The UI implements the "BeforeLeaveObserver" interface (preferred) or
- The UI executes the method addBeforeLeaveListener(BeforeLeaveListener)
This enables to change, deny or delay the navigation.
"BeforeLeaveEvent" has a method "postpone" that puts off the navigation until a condition is met. Then the "ContinueNavigationAction" method resumes the transition. Here is an example from vaadin manual
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class SignupForm extends Div implements BeforeLeaveObserver { @Override public void beforeLeave(BeforeLeaveEvent event) { if (this.hasChanges()) { ContinueNavigationAction action = event.postpone(); ConfirmDialog.build("Are you sure you want to leave this page?") .ifAccept(action::proceed).show(); } } private boolean hasChanges() { // no-op implementation return true; } } |
2.2. Before entering a page ...
Before entering a page can be detected by means of "BeforeEnterEvent" only if- The UI implements the "BeforeEnterObserver" interface (preferred) or
- The UI executes the method addBeforeEnterListener(BeforeEnterListener)
This enables to redirect or deny the navigation in case the user has not been logged or has no permission or maybe if there are no data to display.
This event has a method called "rerouteTo" in order to redirect the navigation. Here is an example from vaadin manual
This event has a method called "rerouteTo" in order to redirect the navigation. Here is an example from vaadin manual
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Class to be rerouted to.. @Route("no-items") public class NoItemsView extends Div { public NoItemsView() { setText("No items found."); } } //Sender class.. @Route("blog") public class BlogList extends Div implements BeforeEnterObserver { @Override public void beforeEnter(BeforeEnterEvent event) { // implementation omitted Object record = getItem(); if (record == null) event.rerouteTo(NoItemsView.class); } private Object getItem() { // no-op implementation return null; } } |
2.3. After navigating to a page ...
After navigating to a page can be detected by means of "AfterNavigationEvent" only if- The UI implements the "AfterNavigationObserver" interface (preferred) or
- The UI executes the method addAfterNavigationListener(AfterNavigationListener)
This enables to updating various parts of the UI once the actual navigation has been completed. Here is an example from vaadin manual
The order of the events are:
Here is the vaadin manual example of a component that uses a RouterLayout as parent. Notice the "@Route(layout property)"
can obviate parents' route. Here are the examples from vaadin tutorial
In this example from vaadin tutorial, executing in the browser "http:8080/MyProject/greet/Emily" it displays "Hello, Emily" where Emily is the parameter
However, this URL will fail if the last parameter (Emily) is not included. It is solved using the @OptionalParameter annotation. The example code is
If more than one parameter is sent, replace the @OptionalParameter annotation with @WildcardParameter
?name1=value1&name2=value2
To use it:
String myRoute=UI.getCurrent().getRouter.getUrl(MyComponent.class)
Note that the getUrl method applies to a Router instance
In case that there are some parameters, the statement is similar (here it is one parameter):
String myRoute=UI.getCurrent().getRouter.getUrl(MyComponent.class,"parameter_to_pass")
Now we can make a link to that URL by means of an Anchor instance
Anchor link= new Anchor (myRoute,"Text to display in the link")
When clicking "Option-2" we get "Hello, Ximo" and when clicking "Option-3" we get "Hello, Paco"
<a router-link href="company"> also reloads the page
1 2 3 4 5 6 7 8 9 10 | public class SideMenu extends Div implements AfterNavigationObserver { Anchor blog = new Anchor("blog", "Blog"); @Override public void afterNavigation(AfterNavigationEvent event) { boolean active = event.getLocation().getFirstSegment() .equals(blog.getHref()); blog.getElement().getClassList().set("active", active); } } |
The order of the events are:
- BeforeLeaveEvent
- BeforeEnterEvent
- AfterNavigationEvent
3. Router Layouts
A RouterLayout component:- Should implement RouterLayout interface
- Supplies his <body> for containing other components that have the property "layout" of the @Route annotation pointing to the parent component (the one implementing the RouterLayout interface)
- Can nest multiple components, displaying only one child, when navigating from one child to another.
Here is the vaadin manual example of a component that uses a RouterLayout as parent. Notice the "@Route(layout property)"
1 2 3 4 | @Tag("div") @Route(value="company", layout=MainLayout.class) public class CompanyComponent extends Component { } |
3.1 Nested Router Layouts
There can be a MainLayout (implementing the RouterLayout interface) that can nest other RouterLayouts. The nested RouterLayouts uses the @ParentLayout that points to its parent Here is the vaadin tutorial example1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //1. Main RouterLayout public class MainLayout extends Div implements RouterLayout { } //2. Nested Routed Layout in the MainLayout @ParentLayout(MainLayout.class) public class MenuBar extends Div implements RouterLayout { public MenuBar() { addMenuElement(TutorialView.class, "Tutorial"); addMenuElement(IconsView.class, "Icons"); } private void addMenuElement(Class<? extends Component> navigationTarget, String name) { // implementation omitted } } //2.1 Nested layout @Route(value = "tutorial", layout = MenuBar.class) public class TutorialView extends Div { } //2.2 Another nested layout @Route(value="icons", layout = MenuBar.class) public class IconsView extends Div { } |
3.2 Route prefixes to RouterLayouts
This is accomplished using the @RoutePrefix("prefix-route") to the RouterLayout. In this example from vaadin manual, the child component can be accessed by the complete route "some/path"1 2 3 4 5 6 7 8 9 10 11 | //Access this component with route to "some/path" @Route(value = "path", layout = SomeParent.class) public class PathComponent extends Div { // Implementation omitted } // Adds the prefix "some" to the routes of its nested components @RoutePrefix("some") public class SomeParent extends Div implements RouterLayout { // Implementation omitted } |
3.3 Absolute routes
Setting the property absolute = true to- @Route annotation or
- @RoutePrefix
can obviate parents' route. Here are the examples from vaadin tutorial
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //Main layout access by route "some" @RoutePrefix("some") public class SomeParent extends Div implements RouterLayout { // Implementation omitted } //Access this component with route to "content" and NOT to "some/content" @Route(value = "content", layout = SomeParent.class, absolute = true) public class MyContent extends Div { // Implementation omitted } //Access by route "framework" and NOT to "some/framework" @RoutePrefix(value = "framework", absolute = true) @ParentLayout(SomeParent.class) public class FrameworkSite extends Div implements RouterLayout { // Implementation omitted } // No absolute route so it is "framework/tutorial" and NOT "some/framework/tutorial" @Route(value = "tutorial", layout = FrameworkSite.class) public class Tutorials extends Div { // Implementation omitted } |
4. URL Parameters
4.1 Parameters
A class can accept parameters in the URL if extends the HasUrlParameter interfaceIn this example from vaadin tutorial, executing in the browser "http:8080/MyProject/greet/Emily" it displays "Hello, Emily" where Emily is the parameter
1 2 3 4 5 6 7 8 9 | @Route(value = "greet") public class GreetingComponent extends Div implements HasUrlParameter<String> { @Override public void setParameter(BeforeEvent event, String parameter) { setText(String.format("Hello, %s!", parameter)); } } |
However, this URL will fail if the last parameter (Emily) is not included. It is solved using the @OptionalParameter annotation. The example code is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Route("greet") public class OptionalGreeting extends Div implements HasUrlParameter<String> { @Override public void setParameter(BeforeEvent event, @OptionalParameter String parameter) { //Will not fail with no parameters if (parameter == null) { setText("Welcome anonymous."); // Uses the parameter if included } else { setText(String.format("Welcome %s.", parameter)); } } } |
If more than one parameter is sent, replace the @OptionalParameter annotation with @WildcardParameter
4.2 Query parameters
We can use query parameters:?name1=value1&name2=value2
To use it:
- Let's locate the method setParameter that is overridden from HasUrlParameter interface
- Get a Location instance from the BeforeEvent
- Get a QueryParameters instance from the Location instance
Here is the example
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Route("greet") public class OptionalGreeting extends Div implements HasUrlParameter<String> { @Override public void setParameter(BeforeEvent event, @OptionalParameter String parameter) { Location location = event.getLocation(); QueryParameters queryParameters = location.getQueryParameters(); Map<String, List<String>> parametersMap = queryParameters.getParameters(); } |
5. URL Generation
To get or produce the URL of any component (that implements the HasUrlParameter) you only have to use this statement for the case it has no parameters:String myRoute=UI.getCurrent().getRouter.getUrl(MyComponent.class)
Note that the getUrl method applies to a Router instance
In case that there are some parameters, the statement is similar (here it is one parameter):
String myRoute=UI.getCurrent().getRouter.getUrl(MyComponent.class,"parameter_to_pass")
Now we can make a link to that URL by means of an Anchor instance
Anchor link= new Anchor (myRoute,"Text to display in the link")
6. Navigation between routes
6.1 routerLink
With the RouterLink we can navigate to another component without knowing its URL route, only knowing its class.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @Route(value = "rlexample") //No need to use the route to the link, only the class name!! public class RouterLinkExample extends VerticalLayout{ public RouterLinkExample() { Div menu = new Div(); // link to a component (MainView2) without parameters menu.add(new RouterLink("Option-1" , MainView2.class)); // link to the component GreetingComponent with a parameter menu.add(new RouterLink("Option-2 ", GreetingComponent.class, "Ximo")); // link to the component GreetingComponent with a parameter menu.add(new RouterLink("Option-3 ", GreetingComponent.class, "Paco")); add(menu); } } //A component class to be routed. @Route(value = "greet") public class GreetingComponent extends Div implements HasUrlParameter<String> { @Override public void setParameter(BeforeEvent event, String parameter) { setText(String.format("Hello, %s!", parameter)); } } |
When clicking "Option-2" we get "Hello, Ximo" and when clicking "Option-3" we get "Hello, Paco"
6.2 Using html "<a href="company">"
RouterLink does not reload the page, but <a href ..> does!<a router-link href="company"> also reloads the page
6.3 Navigation from the server side
There are several options:- UI.navigate(String) that navegates to the route inidicated in the string
- UI.navigate(MyComponent.class) if no parameters
- UI.navigate(MyComponent.class, "myParameter") if there is aparameter
Here is an example, the Greetingcomponent class is the same as the one listed peviously
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @Route(value = "rlexample") public class RouterLinkExample extends VerticalLayout{ public RouterLinkExample() { Div menu = new Div(); menu.add(new RouterLink("Option-1" , MainView2.class)); menu.add(new RouterLink("Option-2 ", GreetingComponent.class, "Ximo")); menu.add(new RouterLink("Option-3 ", GreetingComponent.class, "Paco")); add(menu); //Server routing NativeButton button = new NativeButton("Navigate to Greeting component with no params version 1"); button.addClickListener( e-> { button.getUI().ifPresent(ui -> ui.navigate("greet")); }); add(button); NativeButton button1 = new NativeButton("Navigate to Greeting component with no params version 2"); button1.addClickListener( e-> { button1.getUI().ifPresent(ui -> ui.navigate(GreetingComponent.class)); }); add(button1); NativeButton button2 = new NativeButton("Navigate to Greeting component with params"); button2.addClickListener( e-> { button2.getUI().ifPresent(ui -> ui.navigate(GreetingComponent.class, "Paco")); }); add(button2); } } |
6.4 Getting the routes registered in the application
The Router has the method getRoutes() that retrieves all the registered routes.The RouteData object contains the information form a route.
To obtain the routes by its parent, use getRoutesByParent method
1 2 3 4 5 6 7 8 9 10 11 | // 01. Get the Router instance Router router = UI.getCurrent().getRouter(); // 02. Get the list of routes List<RouteData> routes = router.getRoutes(); // 03. Get all routes by parent Map<Class<? extends RouterLayout>, List<RouteData>> routesByParent = router.getRoutesByParent(); // 04. Filter the routes of one parent List<RouteData> myRoutes = routesByParent.get(MyParentLayout.class); |
7. Page Title on Navigation
To update the page title during navigation can be done with 2 ways:- Using @PageTitle("Title name") annotation at the top of the class or
- Implementing HasDynamicTitle interface and using the overidden method getPageTitle()
8. Router Exception Handling
There are implemented vaadin by default classes to whom are redirected when this exception occurs:
By extending these classes one can customize the results here is a simple example for the first class:
In a dashboard with multiple elements, we can protect an element from unauthorised access raising an AccessDeniedException, but for the moment it is a bit ou of my pretensions. See the tutorial
- Class: RouteNotFoundError for NotFoundException with a 404 code
- Class: InternalServerError for java.lang.Exception with 500 code
By extending these classes one can customize the results here is a simple example for the first class:
1 2 3 4 5 6 7 8 9 10 | @ParentLayout(MainLayout.class) public class CustomNotFoundTarget extends RouteNotFoundError { @Override public int setErrorParameter(BeforeEnterEvent event, ErrorParameter<NotFoundException> parameter) { getElement().setText("My custom not found class!"); return HttpServletResponse.SC_NOT_FOUND; } } |
In a dashboard with multiple elements, we can protect an element from unauthorised access raising an AccessDeniedException, but for the moment it is a bit ou of my pretensions. See the tutorial
No hay comentarios:
Publicar un comentario