【问题标题】:Variable order of components (panels) in JSF pageJSF 页面中组件(面板)的可变顺序
【发布时间】:2019-01-14 21:58:48
【问题描述】:

我想知道在 JSF(或其任何框架,例如 Primefaces)中是否有可能在页面中显示组件或更准确地说是面板的可变顺序。

例如,向用户显示 3 个不同的内容部分(这些是从 1 到 3 的面板)。但是,在设置中,他应该设置这些内容部分的显示顺序(例如,panel3 应该在顶部,panel1 在中间,panel2 在底部)。

我想到的唯一想法是使用组件绑定或某种不可见的排序数据列表,但这些是我宁愿避免的方法,因为它涉及太多变通方法。

【问题讨论】:

  • 为什么不为每个角色定义面板顺序(存储在后端),然后根据用户角色显示面板并继续填充它们?
  • 问题是我有 10 个面板。这给了我们大量可能的组合......而且角色并没有真正影响任何东西。每个用户(与其他用户具有相同的角色)自己设置订单。
  • 在这种情况下,创建一个用户偏好表并让它存储每个用户面板的默认顺序。在 UI 中,为用户提供更改订单的选项,这将更新此表。每次用户加载页面时,此表将用于获取面板及其对各个用户的排序
  • 我不确定我是否理解您的建议。我已经在用户设置的首选项中有一个有序列表。此订单通常保存在数据库中。但是,当我编写 .xhtml 页面时,我将为每个部分提供不同的实现(即不同的面板和不同的组件)。此时,我在 .xhtml 中对渲染顺序进行硬编码。用户在其设置中设置的列表将如何影响这些面板的显示顺序?
  • 所以,你已经完成了第一部分,第二部分,即在 UI 中显示确切的面板需要注意。您可以在 JSF 中创建所有不同的面板及其组件作为单独的复合组件。定义复合组件后,您可以在主 xhtml 文件中包含条件逻辑,该逻辑将查找用户希望在给定位置显示的给定面板类型,并在此基础上启用/显示适当的复合组件- 其中定义了所需的面板和组件。了解复合组件

标签: java jsf primefaces


【解决方案1】:

这实际上在 JSF 中相当简单。该框架使您能够将自己插入生命周期的不同渲染和构建事件中。因此,例如,您可以轻松地使用此功能在视图呈现并发送到浏览器之前对组件进行随机播放。

代码

这是一个定义了五个p:panel 组件的XHTML 页面示例。每次重新加载页面时,组件都会被打乱并以不同的顺序显示。您可以轻松地调整它以按照您喜欢的顺序或根据某些配置设置显示它们;

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui" xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title>Shuffle test</title>
    </h:head>
    <h:body>
        <h:panelGroup>
            <p:panel header="First"/>
            <p:panel header="Second"/>
            <p:panel header="Third"/>
            <p:panel header="Fourth"/>
            <p:panel header="Fifth"/>
            <f:event listener="#{shuffleBackingBean.onShuffle}" type="preRenderComponent" />
        </h:panelGroup>
    </h:body>
</html>

f:event 标签的位置可以看出,我们将自己插入父h:panelGrouppreRenderComponentphase。这允许我们在该组件的渲染阶段之前接收事件。

@Named
@ViewScoped
public class ShuffleBackingBean implements Serializable {
    public void onShuffle(ComponentSystemEvent event) {
        final List<UIComponent> components = new ArrayList<>(event.getComponent().getChildren());
        Collections.shuffle(components);

        event.getComponent().getChildren().clear();
        event.getComponent().getChildren().addAll(components);  
    }
}

上面的支持 bean 定义了 onShuffle 方法,并且在调用时只是随机播放组件。如果你重新加载页面,组件会重新洗牌。

旁注

在组件列表的副本上执行shuffle() 的原因是JSF 使用基于ArrayList 的自定义ChildrenList 类。实现很糟糕,导致Collections.shuffle()IndexOutOfBoundsException 一起崩溃。这只是解决这个问题。

另一种解决方案

解决此问题的另一种方法是依赖某些提供内置排序的组件或使用在h:panelGroup 组件上声明的绑定。这将允许您根据某些设置以编程方式填充此组件。但是,这会将大部分视图定义从 XHTML 文件中移出到 java 类中。如果您的面板中有很多子组件,它也会使事情稍微复杂化,如果它们彼此非常不同,则会使事情变得更加复杂。以编程方式定义所有内容可能非常麻烦。

结论

就我个人而言,我更喜欢插入事件循环并仅移动或修改已在 XHTML 页面中定义的组件(根据上面的代码),因为这会将更多的视图定义移动到它所属的 XHTML 文件中。

【讨论】:

  • 啊!这是完美的,谢谢亚当。正是我正在寻找的...问题实际上很微不足道,如果存在超过 15 年的框架没有这样的功能,那就太可惜了。
  • @VanjaLee 很高兴我能帮上忙。 JSF 非常灵活——这只是解决这个特定问题的方法之一。但正如你所说,这个解决方案很简单,也很容易处理。
  • @AdamWaldenberg:再次,很好的答案。关于实施被“拙劣”,Mojarra 和 MyFaces 都是这种情况,还是您只是检查其中之一?如果是这样,哪一个(也许还添加版本信息。干杯!)
  • @Kukeltje 我只在 Mojara 2.3.3.99 上测试过。但是,我想它在任何地方都几乎相同。我猜ChildrenList 可能忽略了重载一两个方法,导致索引/大小不同步,从而触发shuffle() 调用崩溃。如果 MyFaces 表现不同(并且有人愿意测试),我们可以扩展答案。
猜你喜欢
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多