有条件地渲染取决于 p:selectOneMenu 值

Posted

技术标签:

【中文标题】有条件地渲染取决于 p:selectOneMenu 值【英文标题】:Conditionally render depend on p:selectOneMenu value 【发布时间】:2015-12-18 22:05:25 【问题描述】:

我正在尝试从现有的 Primefaces 组件构建一个自定义组件,我需要一些帮助。我有一个 selectOneMenu,我希望它根据在菜单中选择的选项来呈现或不呈现(并禁用或启用)其他组件。这里的难点是我不能使用托管 Bean 来做到这一点(我有几个原因),我需要一个纯 xhtml 代码。

我尝试了一些 <c:choose><ui:parameter> 的东西来创建布尔值,但由于某种原因,我看不到它不起作用。你们可以看看我的代码,看看你有什么想法吗?可能是一些我想不出来的简单的东西,也可能是我还不知道的东西。

<h:body>
<h:form id="abc">
    <ui:repeat var="pd" value="#produtoMB.produtos">
        <h:panelGroup id="linha">
        <c:choose>
            <c:when test="#pd.marca == X1">
                <c:set var="render" value="#true" />
            </c:when>
            <c:otherwise>
                <c:set var="render" value="#false" />
            </c:otherwise>
        </c:choose>

        <p:selectOneMenu value="#pd.marca">
            <f:selectItem itemLabel="Select One" itemValue="" noSelectionOption="true"/>
            <f:selectItem itemLabel="Xbox One" itemValue="X1" />
            <f:selectItem itemLabel="PlayStation 4" itemValue="PS4" /> 
            <f:selectItem itemLabel="Wii U" itemValue="WU" />
            <p:ajax update="linha" />
        </p:selectOneMenu>
        <p:inputText value="#pd.aparelho" disabled="#render"/>
        <h:outputText value="Microsoft" rendered="#render"/>
        <p:commandButton value="X" />
        </h:panelGroup>
        <br />
    </ui:repeat>
    <br />
    <p:commandButton actionListener="#produtoMB.botaoMais" value="+" update="abc"/>
    <p:commandButton actionListener="#produtoMB.botaoMenos" value="-" update="abc"/>
</h:form>

【问题讨论】:

【参考方案1】:

这里有几个问题。

首先,

<ui:repeat ...>
    <c:choose>
        ...
    </c:choose>
</ui:repeat>

JSTL 标记在视图构建期间运行。在所有 JSF 组件运行之前,它只执行一次。因此,与您对 XML 代码流的直观期望相反,当&lt;ui:repeat&gt; 组件运行和迭代时,它不会被执行。另见JSTL in JSF2 Facelets... makes sense?

第二,

<c:when test="#pd.marca == X1">
...
<f:selectItem ... itemValue="X1" />

itemValue="X1" 代表String。 EL 表达式#X1 基本上分别在 facelet、request、view、session 和 application 范围内查找名为 X1 的变量,直到找到第一个非空值。为了在 EL 中表示 String 值,您需要像 #'X1' 这样用单引号引用它。所以,你应该改用#pd.marca == 'X1'。尽管如此,由于第一点中提到的原因,这仍然行不通。另见Specify conditional rendering of element inside <ui:repeat>? The <c:if> does not seem to work。

但是,您可以使用 &lt;c:set&gt; 在 EL 范围内创建别名,只要您不设置其 scope 属性即可。另见Defining and reusing an EL variable in JSF page。

在删除 JSTL &lt;c:choose&gt; 并修复 EL 表达式 #X1 以表示真正的 String 文字 #'X1' 后,它应该如下所示:

<ui:repeat var="pd" value="#produtoMB.produtos">
    <p:selectOneMenu value="#pd.marca">
        <f:selectItem itemLabel="Select One" itemValue="#null" />
        <f:selectItem itemLabel="Xbox One" itemValue="X1" />
        <f:selectItem itemLabel="PlayStation 4" itemValue="PS4" /> 
        <f:selectItem itemLabel="Wii U" itemValue="WU" />
        <p:ajax update="linha" />
    </p:selectOneMenu>
    <h:panelGroup id="linha">
        <c:set var="marcaIsX1" value="#pd.marca eq 'X1'" />
        <p:inputText value="#pd.aparelho" disabled="#marcaIsX1" />
        <h:outputText value="Microsoft" rendered="#marcaIsX1" />
    </h:panelGroup>
    <p:commandButton value="X" />
</ui:repeat>

请注意,我还删除了未使用的 noSelectionOption="true" 并移动了 &lt;h:panelGroup id="linha"&gt; 以包装真正需要更新的组件。

【讨论】:

Balus,非常感谢您的回答。这确实是一个更有意义的解决方案(出于某种原因,我什至没有考虑在每个“禁用”和“渲染”属性中写入条件的想法。在得到你的答案之前,我注意到我在 EL 表达式中的错误, 但也谢谢你!我真的很希望 能像我想的那样工作,但我们不能拥有我们想要的一切,对吧?;-) 非常感谢,你拯救了这一天! Baulus,您是否认为有一种方法可以创建布尔变量并按照我第一次的意图使用它们,也许与 JSTL 标记不同?只是好奇:我现在解决了我的问题,但我正在考虑不同的场景,我需要回到我原来的想法...... 只使用&lt;c:set var="x1selected" value="#pd.marca == 'X1'" /&gt; 而不使用整个&lt;c:choose&gt; 块。另见***.com/q/6434866

以上是关于有条件地渲染取决于 p:selectOneMenu 值的主要内容,如果未能解决你的问题,请参考以下文章

React Router VS 条件渲染

根据 p:dataTable 的每一行中的另一个 p:selectOneMenu 填充 p:selectOneMenu

Primefaces valueChangeListener 或 <p:ajax 侦听器未触发 p:selectOneMenu [重复]

p:selectOneMenu在p:面板中保存后无负载正确

标签文件中的条件渲染取决于是不是指定了属性

PrimeFaces p:selectOneMenu宽度