Vaadin Flow:使用 SplitLayout 和 @ParentLayout 时导航中断(?)
Vaadin Flow: Navigation broken(?) when using SplitLayout and @ParentLayout
[EDIT] 问题结尾的解决方案[/EDIT]
上下文
我目前正在努力实现基于 SplitLayout
的 Component
,如下所示:
当时的想法是,带有 class="outer"
(突出显示的行)的布局将作为内容的占位符,当用户选择 Grid
中的一行时,应该加载这些内容。
"outer"-Layout
已添加到网格旁边的 SplitLayout
,因此标记为 slot='secondary'
。
另一个 class 引用 'outer'-Layout
和 @Route(value = "details", layout = OuterLayout.class)
通过单击 Grid
的条目,页面导航至 "grid/details"
。
问题:
我希望 Vaadin 将带注释的 class 的内容放在 'outer'-Layout
中,但它会在其旁边添加一个新条目:
如果我删除第一个 'outer'-Layout
Vaadin 将第二个标记为 slot='secondary'
并且其内容出现:
它甚至根据当前选择的 Gridentry 进行更新...
来源:
拆分布局
@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*/
}
}
我是不是误解了生命周期的概念?
提前致谢
解决方案
根据 Tatu Lund 的建议,我修改了 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()));
}
}
}
在像您这样的情况下使用 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
,它们不是路由目标。
这里有更多信息:https://vaadin.com/docs/v12/flow/routing/tutorial-router-layout.html and here: https://vaadin.com/tutorials/nested-layouts-in-flow
[EDIT] 问题结尾的解决方案[/EDIT]
上下文
我目前正在努力实现基于 SplitLayout
的 Component
,如下所示:
当时的想法是,带有 class="outer"
(突出显示的行)的布局将作为内容的占位符,当用户选择 Grid
中的一行时,应该加载这些内容。
"outer"-Layout
已添加到网格旁边的 SplitLayout
,因此标记为 slot='secondary'
。
另一个 class 引用 'outer'-Layout
和 @Route(value = "details", layout = OuterLayout.class)
通过单击 Grid
的条目,页面导航至 "grid/details"
。
问题:
我希望 Vaadin 将带注释的 class 的内容放在 'outer'-Layout
中,但它会在其旁边添加一个新条目:
'outer'-Layout
Vaadin 将第二个标记为 slot='secondary'
并且其内容出现:
来源:
拆分布局
@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*/
}
}
我是不是误解了生命周期的概念?
提前致谢
解决方案
根据 Tatu Lund 的建议,我修改了 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()));
}
}
}
在像您这样的情况下使用 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
,它们不是路由目标。
这里有更多信息:https://vaadin.com/docs/v12/flow/routing/tutorial-router-layout.html and here: https://vaadin.com/tutorials/nested-layouts-in-flow