[EDIT] Solution at the end of the question [/EDIT]
Context
I currently struggle to implement a Component which is based on the SplitLayout that looks like this:

The idea was that the layout with the class="outer" (the highlighted line) would be a placeholder for content that was supposed to be loaded when the user selects a line in the Grid.
The "outer"-Layout was added to to SplitLayout alongside the grid and is therefore marked with slot='secondary'.
Another class references the 'outer'-Layout with @Route(value = "details", layout = OuterLayout.class)
By clicking on an entry of the Grid the page navigates to "grid/details".
Problem:
I expected Vaadin to place the contents of the annotated class within the 'outer'-Layout but instead it adds a new entry next to it:
If I remove the first 'outer'-Layout Vaadin tags the second one as slot='secondary' and its content appears:
Its even updating according the currently selected Gridentry...
Sources:
Splitlayout
@Route(value = "grid", layout = ContentLayout.class)
@ParentLayout(ContentLayout.class)
public class MySplitLayout extends SplitLayout implements RouterLayout {
private MyGrid grid;
private MyDetailOuterLayout detailOuterLayout;
public MySplitLayout() {
setSizeFull();
grid = new MyGrid();
detailOuterLayout = new MyDetailOuterLayout();
addToPrimary(grid);
addToSecondary(detailOuterLayout);
}
}
Outer
@ParentLayout(MySplitLayout.class)
public class MyDetailOuterLayout extends FlexLayout implements RouterLayout{
public MyDetailOuterLayout() {
setClassName("outer");
}
}
Inner
@Route(value = "grid/details", layout = MyDetailOuterLayout.class)
public class MyDetailLayout extends FlexLayout
implements HasUrlParameter<Integer>, BeforeEnterObserver
{
public MonitorDetailLayout() {
setClassName("inner");
/* define data via URL*/
}
}
Did I misunderstand the lifecycle concept?
Thank you in advance
Solution
As suggested by Tatu Lund I modified the default implementation of RouterLayout like this:
@Route(value = "grid", layout = ContentLayout.class)
@ParentLayout(ContentLayout.class)
public class MySplitLayout extends SplitLayout implements RouterLayout {
private MyGrid grid;
private MyDetailOuterLayout detailOuterLayout;
public MySplitLayout() {
setSizeFull();
grid = new MyGrid();
detailOuterLayout = new MyDetailOuterLayout();
addToPrimary(grid);
addToSecondary(detailOuterLayout);
}
@Override
public void showRouterLayoutContent(HasElement content) {
if (content != null) {
Element rootElement = getElement();
rootElement.removeChild(detailOuterLayout.getElement()); // aka the secondary Element
rootElement.appendChild(Objects.requireNonNull(content.getElement()));
}
}
}
The idea with
RouterLayoutuse in cases like you have is that, you need to overrideshowRouterLayoutContent(..)method. When navigation happens, this method is called and it does place the content where you navigated to, into the layout. So in your case I assume you need a route target, which wraps the Grid.So pattern is like this, e.g. in your main layout you need to have the content holder, here it is Div, but it can be anything (like SplitLayout, or what ever)
Also note, if you are using
@Route(value="..", layout = ParentLayout.class)annotation, you should not use@ParentLayout(ParentLayout.class)together with it. You need to use@ParentLayoutonly for classes, that are not Route targets.There is some more information here: https://vaadin.com/docs/v12/flow/routing/tutorial-router-layout.html and here: https://vaadin.com/tutorials/nested-layouts-in-flow