Skip to content

Commit

Permalink
fix: Update layout document
Browse files Browse the repository at this point in the history
Add documenatation on RouterLayout
functionality.
Update source samples and add
reference links.

Closes #3819
  • Loading branch information
caalador committed Jan 17, 2025
1 parent c11ae77 commit 520bd42
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 15 deletions.
6 changes: 3 additions & 3 deletions articles/components/app-layout/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ With Flow, the root layout can be defined using the <<{articles}/flow/routing/la
[source,java]
----
@Layout
public class MainLayout extends AppLayout implements RouterLayout {
public class MainLayout extends AppLayout {
}
----
Expand Down Expand Up @@ -138,7 +138,7 @@ The `navbar` is a header above the content area. It can contain primary or secon
----
<source-info group="Flow"></source-info>
@Layout
public class MainLayout extends AppLayout implements RouterLayout {
public class MainLayout extends AppLayout {
public MainLayout() {
H1 title = new H1("My App");
addToNavbar(title);
Expand Down Expand Up @@ -233,7 +233,7 @@ The `drawer` can switch between a fixed area next to the view's content and an e
----
<source-info group="Flow"></source-info>
@Layout
public class MainLayout extends AppLayout implements RouterLayout {
public class MainLayout extends AppLayout {
public MainLayout() {
SideNav nav = new SideNav();
addToDrawer(nav);
Expand Down
132 changes: 120 additions & 12 deletions articles/flow/routing/layout.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,37 @@ order: 40

= Router Layouts & Nested Router Targets

All parent layouts of a navigation target component have to implement the [interfacename]`RouterLayout` interface. You can define a parent layout by adding the [annotationname]`@Layout` annotation to the class, or by using the optional element `layout` from the `@Route` annotation.
All parent layouts of a navigation target component have to implement the [interfacename]`RouterLayout` interface.
You can define a parent layout by adding the [annotationname]`@Layout` annotation to the class, or by using the optional element `layout` from the `@Route` annotation.

[interfacename]`RouterLayout` interface automatically appends and removes child route content during navigation. For more indepth information see <<#Router Layout,Router Layout>>.

Check failure on line 15 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'indepth'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'indepth'?", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 15, "column": 123}}}, "severity": "ERROR"}


[role="since:com.vaadin:[email protected]"]
=== Automatic Layout Using `@Layout`

The value for the [annotationName]`@Layout` annotation path has to be unique for the project. Otherwise, the resolver won't be able to determine which layout component should be used. Having multiple [annotationName]`@Layout` annotations with the same path throws an exception.
The [annotationName]`@Layout` can be put on any [className]`Component` that implements [interfacename]`RouterLayout`.

The example below renders all routes inside [classname]`MainLayout`:

[source,java]
----
@Layout
public class MainLayout extends Div
implements RouterLayout {
public class MainLayout extends AppLayout {
}
----

If the application is using access protection, the view access is checked for the Layout, as well as the view. To make the layout accessible, add [annotationname]`@AnonymousAllowed` -- or some other access annotation -- on the `MainLayout` so that the request is not denied.
See <<{articles}/components/app-layout/#,AppLayout>> for more information on usage.

Check failure on line 32 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.ProductName] Use 'App Layout' instead of 'AppLayout'. Raw Output: {"message": "[Vaadin.ProductName] Use 'App Layout' instead of 'AppLayout'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 32, "column": 42}}}, "severity": "ERROR"}

The value for the [annotationName]`@Layout` annotation path has to be unique for the project. Otherwise, the resolver won't be able to determine which layout component should be used.
Having multiple [annotationName]`@Layout` annotations with the same path throws an exception.

If the application is using access protection, the view access is checked for the Layout, as well as the view.
To make the layout accessible, add [annotationname]`@AnonymousAllowed` -- or some other access annotation -- on the `MainLayout` so that the request is not denied.

[annotationname]`@Route` and [annotationname]`@RouteAlias` each contain an annotation attribute called, `autoLayout`. Setting that attribute to false will stop automatic layout; it will ignore any [annotationname]`@Layout` matching the route. Giving a class for the `layout` method in [annotationname]`@Route` also disables automatic layout and uses the one given.
[annotationname]`@Route` and [annotationname]`@RouteAlias` each contain an annotation attribute called, `autoLayout`.
Setting that attribute to false will stop automatic layout; it will ignore any [annotationname]`@Layout` matching the route.

Check warning on line 41 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 41, "column": 33}}}, "severity": "WARNING"}

Check warning on line 41 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 41, "column": 64}}}, "severity": "WARNING"}
Giving a class for the `layout` method in [annotationname]`@Route` also disables automatic layout and uses the one given.

.Ignore Automatic Layout
[source,java]
Expand Down Expand Up @@ -87,19 +97,18 @@ See <<page-titles#,Updating Page Title on Navigation>> for more information on t

Use the `@ParentLayout` annotation to define a parent layout for components in the routing hierarchy. Where necessary, a parent can have its own parent layout.

In the example below, `MainLayout` is used for everything, which `MenuBar` is reused for views:
In the example below, `MainLayout` is used for everything, and `SubMenu` is reused for views:

[source,java]
----
public class MainLayout extends Div
implements RouterLayout {
public class MainLayout extends AppLayout {
}
@Layout
@ParentLayout(MainLayout.class)
public class MenuBar extends Div
public class SubMenu extends Div
implements RouterLayout {
public MenuBar() {
public SubMenu() {
addMenuElement(TutorialView.class, "Tutorial");
addMenuElement(IconsView.class, "Icons");
}
Expand All @@ -119,7 +128,7 @@ public class IconsView extends Div {
}
----

`MainLayout` encapsulates `MenuBar`, which in turn encapsulates `TutorialView` or `IconsView` -- depending on where the user has navigated.
`MainLayout` encapsulates `SubMenu`, which in turn encapsulates `TutorialView` or `IconsView` -- depending on where the user has navigated.


== ParentLayout Route Control
Expand Down Expand Up @@ -181,4 +190,103 @@ The bound route is `framework/tutorial`, although the full chain is `some/framew

If a parent layout defines a `@RoutePrefix`, the "default" child could have its route defined as `@Route("")` and be mapped to the parent layout route. For example, `Tutorials` with route `""` would be mapped as `framework/`.


=== Router Layout

A class implementing the [interfacename]`RouterLayout` interface will automatically append and remove content on navigation to a route with the layout in the parent stack.

Check warning on line 196 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 196, "column": 66}}}, "severity": "WARNING"}

By default, the content will be appended to the [interfacename]`RouterLayout` component, so anything added on navigation will be positioned last.

Check warning on line 198 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 198, "column": 25}}}, "severity": "WARNING"}

Check warning on line 198 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 198, "column": 122}}}, "severity": "WARNING"}

.Layout Order Sample
[source,java]
----
public class ParentLayout extends Div implements RouterLayout {
public ParentLayout() {
add(new Span("Parent content"));
}
}
@Route(value = "route", layout = ParentLayout.class)
public class MyRoute extends Div {
public MyRoute() {
add(new Span("View content"));
}
}
----

.Sample Output
[source,text]
----
Parent content
View content
----

Adding elements after navigation in the parent will put the content after the view content.

Check warning on line 224 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 224, "column": 48}}}, "severity": "WARNING"}

.Layout Order Sample
[source,java]
----
public class ParentLayout extends Div implements RouterLayout {
public ParentLayout() {
add(new Span("Parent content"));
}
@Override
protected void onAttach(AttachEvent attachEvent) {
add(new Span("On attach"));
}
}
@Route(value = "route", layout = ParentLayout.class)
public class MyRoute extends Div {
public MyRoute() {
add(new Span("View content"));
}
}
----

.Sample Output
[source,text]
----
Parent content
View content
On attach
----

To customise content position the method [methodname]`showRouterLayoutContent(HasElement content)` can be overridden.
Even with [methodname]`showRouterLayoutContent` overridden the content will be automatically removed from the component on navigation if not part of the new route.

Check warning on line 257 in articles/flow/routing/layout.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vaadin.Will] Avoid using 'will'. Raw Output: {"message": "[Vaadin.Will] Avoid using 'will'.", "location": {"path": "articles/flow/routing/layout.adoc", "range": {"start": {"line": 257, "column": 72}}}, "severity": "WARNING"}

.Custom Content Sample
[source,java]
----
public class ParentLayout extends Div implements RouterLayout {
private Div childHolder = new Div();
public ParentLayout() {
add(childHolder, new Span("Parent content"));
}
@Override
public void showRouterLayoutContent(HasElement content) {
if(content != null) {
childHolder.getElement().appendChild(content.getElement());
}
}
}
@Route(value = "route", layout = ParentLayout.class)
public class MyRoute extends Div {
public MyRoute() {
add(new Span("View content"));
}
}
----

.Sample Output
[source,text]
----
View content
Parent content
----

[discussion-id]`7A96749F-CD19-4422-A2A2-B4ACD719C9FA`

0 comments on commit 520bd42

Please sign in to comment.