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".


Проблема:

Я ожидал, что Vaadin поместит содержимое аннотированного класса в 'outer'-Layout, но вместо этого он добавляет новую запись рядом с ним:  введите описание изображения здесь Если я удалю первый 'outer'-Layout Vaadin пометит второй как slot='secondary' и отображается его содержимое:  введите описание изображения здесь Его даже обновление в соответствии с текущим выбранным Gridentry ...


Источники:

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()));
        }
    }

}

person Gerrit Sedlaczek    schedule 31.01.2019    source источник


Ответы (1)


Идея использования RouterLayout в таких случаях, как у вас, заключается в том, что вам нужно переопределить метод showRouterLayoutContent(..). Когда происходит навигация, вызывается этот метод, и он помещает контент, к которому вы перешли, в макет. Итак, в вашем случае я предполагаю, что вам нужна цель маршрута, которая обертывает сетку.

Итак, шаблон выглядит так, например. в вашем основном макете вам нужен держатель контента, здесь это 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

person Tatu Lund    schedule 01.02.2019
comment
Большое тебе спасибо. Добавил решение в конец вопроса. - person Gerrit Sedlaczek; 01.02.2019
comment
Кстати, если я опущу аннотацию @ParentLayout на MySplitLayout, он станет корневым элементом, если я перейду к "grid/details" и удаляю ContentLayout и его родителей. - person Gerrit Sedlaczek; 01.02.2019