我遇到一个问题,即即使我没有渲染复合材料,也会触发复合面的验证。
我将问题解决了以下准系统代码。
这是复合entityDetailPanel
:
<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:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:common="http://java.sun.com/jsf/composite/common">
<composite:interface>
<composite:attribute name="prefix" required="true" />
<composite:facet name="lowerPanel"/>
</composite:interface>
<composite:implementation>
<h:form id="#{cc.attrs.prefix}entityDetailForm2"
styleClass="#{cc.attrs.prefix}EntityDetailPanelForm #{cc.attrs.prefix}Listener" >
<p:messages id="#{cc.attrs.prefix}messages" autoUpdate="true" closable="true"/>
<p:commandButton
value="SAVE"
update="@(.#{cc.attrs.prefix}Listener), @(.#{cc.attrs.prefix}EntityDetailPanelForm}"/>
<composite:renderFacet name="lowerPanel" rendered="false"/>
</h:form>
</composite:implementation>
</ui:composition>
这是调用:
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:common="http://xmlns.jcp.org/jsf/composite/common">
<common:entityDetailPanel id="foo" prefix="Instruments">
<f:facet name="lowerPanel">
<!-- <p:inputText id="assetClassPrompt" required="true" requiredMessage="Why do we get this message?"/>-->
<p:selectOneMenu id="assetClassPrompt" required="true" requiredMessage="Why do we get this message?"
value="#{instrumentController.selectedData.assetClass}">
<f:selectItem itemLabel="foo" itemValue="foo"/>
<f:selectItem itemLabel="bar" itemValue="bar"/>
</p:selectOneMenu>
</f:facet>
</common:entityDetailPanel>
</ui:composition>
组合框没有显示在屏幕上(因为它没有渲染),但为什么我会对未渲染的内容进行验证呢?
这是我点击“保存”按钮时看到的内容:
更奇怪的是,即使在没有那个组合框的复合材料的其他调用中,我也看到了这个验证错误。
我还注意到,如果我在<messages>
标记上没有包含唯一ID,则使用复合的消息将显示在合成的其他用途中。
这是PrimeFaces还是JSF错误,还是我错过了什么?
您可能会注意到我有一个已注释的<inputText>
标记。值得一提的是,当我替换<selectOneMenu>
并将其替换为<inputText>
时,我不再看到问题。
我认为可能有助于澄清我试图解决的更大问题。
我想创建类似于<p:layout>
的东西,它既包含固定元素(对于复合材料的所有用途),也包含以参数方式传递的非固定元素/面板(对于组件的每次使用)。
这是一个屏幕截图,其中read中指示的项目随着复合的每次调用而变化。其他所有内容始终存在于复合材料的所有调用中。
如您所见,参数为:
答案 0 :(得分:4)
这个问题是双重的。
首先,<cc:renderFacet>
从未设计为以这种方式工作。它does not支持rendered
属性。它以某种方式工作是因为facet在内部被重新解释为UIPanel
组件,并且所有属性(错误地)自动从标签继承。你不应该依赖它。渲染响应期间错误地考虑了rendered
属性,导致其“工作”的混乱行为。这在技术上是JSF实现中的一个错误。在回发期间,属性(正确)不继承,导致您观察到的麻烦。这些组件仍然被解码和验证“尽管”它们没有被渲染。
其次,<p:inputText>
从UIInput
延伸,在验证之前检查是否有任何提交的值。提交的值null
被解释为完全没有表单中的输入字段,因此它被跳过。提交的空字符串值作为空值进行处理,因此已经过验证。但是,<p:selectOneMenu>
已覆盖标准UIInput
行为,并将null
视为与空字符串相同的方式。即使提交的值为null
(这意味着输入字段根本不在表单中),它仍然在被验证。这在技术上是PrimeFaces方面的一个错误。
你的意图至少是明确的:有条件地渲染一个方面。在Facelets编译时(这是视图构建时间之前的一个步骤)期间评估<cc:xxx>
标记,因此使用JSTL <cc:renderFacet>
有条件地构建<c:if>
也将无法工作。
您最好的选择是将“渲染下方面板”重新定义为复合属性,并创建一个支持组件,以便在将该属性添加到视图后将其显式复制到构面中。
<cc:interface componentType="entityDetailPanelComposite">
...
<cc:facet name="lowerPanel" />
<cc:attribute name="renderLowerPanel" type="java.lang.Boolean" default="false" />
</cc:interface>
<cc:implementation>
<f:event type="postAddToView" listener="#{cc.init}" />
...
<cc:renderFacet name="lowerPanel" />
...
</cc:implementation>
@FacesComponent("entityDetailPanelComposite")
public class EntityDetailPanelComposite extends UINamingContainer {
public void init() {
UIComponent lowerPanel = getFacets().get("lowerPanel");
ValueExpression renderLowerPanel = getValueExpression("renderLowerPanel");
if (renderLowerPanel != null) {
lowerPanel.setValueExpression("rendered", renderLowerPanel); // It's an EL expression.
} else {
lowerPanel.getAttributes().put("rendered", getAttributes().get("renderLowerPanel")); // It's a literal value, or the default value.
}
}
}
这有额外的好处,您可以从客户端指定它。
<my:entityDetailPanel ... renderLowerPanel="true" />