Vaadin Flow: навигация не работает (?) При использовании SplitLayout и @ParentLayout
[EDIT] Решение в конце вопроса [/EDIT]
контекст
В настоящее время я борюсь за реализацию Component
который основан на SplitLayout
это выглядит так:
Идея заключалась в том, что макет с class="outer"
(выделенная строка) будет заполнителем для контента, который должен был быть загружен, когда пользователь выбирает строку в Grid
,
"outer"-Layout
был добавлен в SplitLayout
рядом с сеткой и поэтому помечены slot='secondary'
,
Другой класс ссылается на 'outer'-Layout
с @Route(value = "details", layout = OuterLayout.class)
Нажав на запись Grid
страница переходит к "grid/details"
,
Проблема:
Я ожидал, что Ваадин поместит содержимое аннотированного класса в 'outer'-Layout
но вместо этого он добавляет новую запись рядом с ним: Если я уберу первый 'outer'-Layout
Ваадин отмечает второй как slot='secondary'
и его содержание появляется: Его даже обновление в соответствии с выбранным в настоящее время Гридентри...
Источники:
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);
}
}
внешний
@ParentLayout(MySplitLayout.class)
public class MyDetailOuterLayout extends FlexLayout implements RouterLayout{
public MyDetailOuterLayout() {
setClassName("outer");
}
}
внутренний
@Route(value = "grid/details", layout = MyDetailOuterLayout.class)
public class MyDetailLayout extends FlexLayout
implements HasUrlParameter<Integer>, BeforeEnterObserver
{
public MonitorDetailLayout() {
setClassName("inner");
/* define data via URL*/
}
}
Я неправильно понял концепцию жизненного цикла?
заранее спасибо
Решение
По предложению Тату Лунда я изменил реализацию по умолчанию RouterLayout
как это:
@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()));
}
}
}
1 ответ
Идея с RouterLayout
использовать в случаях, как у вас есть, вы должны переопределить showRouterLayoutContent(..)
метод. Когда происходит навигация, вызывается этот метод, и он помещает контент, к которому вы перешли, в макет. Так что в вашем случае я предполагаю, что вам нужна цель маршрута, которая оборачивает Grid.
Таким образом, шаблон такой: например, в вашем основном макете вам нужно иметь держатель контента, здесь это Div, но это может быть что угодно (например, SplitLayout или что-то еще)
public class MainLayout extends VerticalLayout implements RouterLayout {
private Div childWrapper = new Div();
@Override
public void showRouterLayoutContent(HasElement content) {
childWrapper.getElement().appendChild(content.getElement());
}
}
Также обратите внимание, если вы используете @Route(value="..", layout = ParentLayout.class)
аннотации, вы не должны использовать @ParentLayout(ParentLayout.class)
вместе с этим. Вам нужно использовать @ParentLayout
только для классов, которые не являются целями Route.
Здесь есть дополнительная информация: https://vaadin.com/docs/v12/flow/routing/tutorial-router-layout.html и здесь: https://vaadin.com/tutorials/nested-layouts-in-flow