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

Conditionally render depend on p:selectOneMenu value

我正在尝试从现有的 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>

这里有几个问题。

首先,

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

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

第二,

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

中的itemValue="X1"代表一个String。 EL 表达式 #{X1} 基本上分别在 facelet、请求、视图、会话和应用程序范围中查找名为 X1 的变量,直到找到第一个非空值。为了在 EL 中表示 String 值,您需要用单引号将其引用,例如 #{'X1'}。所以,你应该使用 #{pd.marca == 'X1'} 来代替。尽管如此,由于第一点中提到的原因,这仍然行不通。另见 Specify conditional rendering of element inside <ui:repeat>? The <c:if> does not seem to work.

然而,您可以使用 <c:set> 在 EL 范围内创建别名,只要您不设置其 scope 属性即可。另见 Defining and reusing an EL variable in JSF page.

删除 JSTL <c:choose> 并修复 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" 并移动了 <h:panelGroup id="linha"> 以包装 真正需要更新的组件。