【问题标题】:Setting ui:param conditionally有条件地设置 ui:param
【发布时间】:2013-12-04 10:10:45
【问题描述】:

我想根据 bean 值设置一个 ui:param,我认为使用 c:if 是个好主意。所以我在我的页面中输入了以下代码:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:wai="http://www.id.ethz.ch/wai/jsf"
    template="/view/listView.xhtml">

        <c:if test="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}">
         <ui:param name="title" value="#{msg.subscriptionTitleMySubscriptions}"/>
        </c:if>
        <c:if test="#{subscriptionListController.model.listViewName eq 'paidSubscriptions'}">
         <ui:param name="title" value="#{msg.subscriptionTitlePaidSubscriptions}"/>
        </c:if>
        <c:if test="#{subscriptionListController.model.listViewName eq 'allSubscriptions'}">
         <ui:param name="title" value="#{msg.subscriptionTitleAllSubscriptions}"/>
        </c:if>
        ....

但是参数没有设置...

如果我打印出 #{subscriptionListController.model.listViewName eq 'mySubscriptions'} 的值,我在相应的情况下得到 true,在其他两种情况下得到 false。

一开始我只有2种可能,用三元运算符解决了:

<ui:param name="title" value="#{subscriptionListController.model.listViewName eq 'mySubscriptions' ? msg.subscriptionTitleMySubscriptions : msg.subscriptionTitlePaidSubscriptions}"/>

它奏效了。但现在我有了更多的可能性……

我做错了什么?

【问题讨论】:

  • 您不清楚它何时工作/失败。 &lt;c:if&gt;s 看起来不错,但 &lt;c:otherwise&gt; 完全放错了位置。它属于&lt;c:choose&gt;。代码似乎也不完整,这似乎是一个模板客户端,但我没有看到&lt;ui:define&gt;。您知道 Facelets 会忽略 &lt;ui:define&gt;&lt;ui:composition&gt; 之外的任何内容吗?
  • &lt;ui:composition&gt; 在那里(参见代码的第一行),因此不应忽略它。我删除了&lt;c:otherwise&gt; 并添加了c:if。但它仍然不起作用......正如所说,三元运算符没有问题,但c:if nope......(我编辑了我的代码,因为标题的值是错误的)
  • @BalusC 好的,&lt;ui:define&gt; 定义如下。我在那里转移了c:ifcode,现在它可以工作了!但是你现在能解释一下为什么要用燕鸥吗?同上。虽然它在&lt;ui:define&gt; 之外也可以工作?此外,我在它之外定义了其他 ui:param(就在 c:if 下方)并且它们工作......
  • @BalusC 您能否将您的评论放入答案中,以便我接受?

标签: jsf-2 primefaces facelets


【解决方案1】:

&lt;ui:composition template&gt;所示,此页面代表一个模板客户端。

&lt;ui:define&gt; 之外的任何&lt;ui:param&gt; 都适用于主模板(您在template 属性中声明的文件),并在模板客户端本身内部被忽略。如果你打算在模板客户端内部准备变量,你应该把&lt;ui:param&gt;放在&lt;ui:define&gt;里面。

但还有一件事:&lt;ui:param&gt; 的最初目的是将变量传递给 &lt;ui:composition template&gt;&lt;ui:decorate template&gt;&lt;ui:include src&gt; 引用的文件,而不是在当前 facelet 上下文中准备/设置变量。对于在当前 EL 上下文中准备/设置变量的唯一功能要求,您最好使用 JSTL &lt;c:set&gt; 来完成这项工作。您可以为此使用&lt;ui:param&gt;,但这不是它的初衷,在旧版 MyFaces 中也不是这样。

所以,所以:

<ui:define>
    <c:if test="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}">
        <c:set var="title" value="#{msg.subscriptionTitleMySubscriptions}"/>
    </c:if>
    <c:if test="#{subscriptionListController.model.listViewName eq 'paidSubscriptions'}">
        <c:set var="title" value="#{msg.subscriptionTitlePaidSubscriptions}"/>
    </c:if>
    <c:if test="#{subscriptionListController.model.listViewName eq 'allSubscriptions'}">
        <c:set var="title" value="#{msg.subscriptionTitleAllSubscriptions}"/>
    </c:if>
    ...
</ui:define>

与具体问题无关,您可以按如下方式对其进行优化,而不需要一个无法维护的&lt;c:if&gt; 组,该组只会随着每种订阅类型而增长:

<ui:define>
    <c:set var="subscriptionTitleKey" value="subscriptionTitle.#{subscriptionListController.model.listViewName}">
    <c:set var="title" value="#{msg[subscriptionTitleKey]}"/>
    ...
</ui:define>

用那些键

subscriptionTitle.mySubscriptions = Title for my subscriptions
subscriptionTitle.paidSubscriptions = Title for paid subscriptions
subscriptionTitle.allSubscriptions = Title for all subscriptions

【讨论】:

  • "... 反过来在技术上是错误的,并且仅在 Mojarra 中有效,但在 MyFaces 中无效..." 这不是真的。相反,情况恰恰相反。这是一个 looooonnngggg 的故事,但我已将原因写在 MYFACES-3169 中。最近在MYFACES-3810 中,它在 2.2.x 分支中添加了一个标志以启用旧行为。 ui:param 仅适用于 ui:include、ui:decorate 或 ui:composition 的直接子级,但参数在目标模板的上下文中可用。在 c:if 中使用它们是个坏主意。
  • @lu:顺便说一句,我也同意我们应该真正保留&lt;c:set&gt;。非常感谢它在固定范围(请求/视图/会话/应用程序)中存储评估值的能力。 &lt;ui:param&gt; 不支持它(每次访问都会重新评估表达式),而且标签名称“param”本身并没有真正自我记录“在 EL 上下文中设置变量”的功能要求"。
  • 绝对,c:set 确实很有用。我们在 MyFaces 中所做的是修复 c:set 以在没有像 JSP 中那样设置范围时使用页面范围,并创建一个“模板上下文”来存储 ui:param 变量。 c:set 和 ui:param 仍然依赖于 EL VariableMapper 工具,并被视为构建视图时间标签。如果没有这个修复,EL 缓存等一些优化将无法正确完成。真的 ui:param 是一个标签,用于将参数作为 EL 表达式传递给模板。
【解决方案2】:

您正在将 JSTL 与 Facelets 一起使用。 JSTL 在视图构建期间执行,而不是在渲染阶段。此外,在 JSF2 库中处理它们存在一些问题——比如在旧的 Mojarra 版本中,它们不能处理部分状态保存的视图范围 bean——参见https://stackoverflow.com/a/3343681)。这就是您的 EL 表达式起作用的原因。

解决方案是避免使用 JSTL - 使用 ui:repeat 代替 c:forEach 和 EL 表达式和条件渲染而不是 c:if。

【讨论】:

  • 感谢您的解释,但是如何使用 ui:param 进行条件渲染?
  • @Francesco primefaces 组件,以及 ui:fragment 具有 'rendered' 属性,采用 EL 表达式。
  • 好吧,我看到 ui:param 也有渲染属性(我没想到...)
  • 嗯,现在我有&lt;ui:param name="title" value="#{msg.subscriptionTitleMySubscriptions}" rendered="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}"/&gt;(三种可能性不同),但它不起作用。现在总是选择三个中的最后一个......
  • 我也尝试指定 true, false, false 而不是检查EL,但是虽然最后是false,它是“渲染”的那个
猜你喜欢
  • 1970-01-01
  • 2017-05-28
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
相关资源
最近更新 更多