Primefaces outputLabel用于复合组件

时间:2013-02-21 12:36:41

标签: jsf-2 primefaces composite-component

与复合组件一起使用时,我遇到使用p:outputLabel的问题。我有p:inputText字段的复合组件(我从组件中删除了不相关的部分):

<cc:interface>
  <cc:editableValueHolder name="myInput" targets="myInput"/>
  <cc:attribute name="required" required="true" type="java.lang.Boolean" default="false"/>
</cc:interface>

<cc:implementation>
  <p:inputText id="myInput" required="#{cc.attrs.required}"/>
</cc:implementation>

现在,我不会将此组件与p:outputLabel

一起使用
<p:outputLabel for="myComponent:myInput" value="#{resources['myLabel']}:"/>
<my:myComponent id="myComponent" required="#{myBean.required}"/>

一切正常,需要验证,也会显示消息,但标签上没有*符号,因为我将标签直接连接到p:inputText组件时。另一方面,如果我在required="true"上硬编码p:inputText,一切正常。

我通过org.primefaces.component.outputlabel.OutputLabelRenderer进行了调试,发现该组件被识别为UIInput,但input.isRequired()返回false。进一步调试发现required属性尚未在组件上定义,因此它返回false作为默认值i UIInput

(Boolean) getStateHelper().eval(PropertyKeys.required, false);

另外,如果我只是在复合组件中移动p:outputLabel,一切正常。像EL一样,以后会在复合组件内进行评估吗?

我正在使用Primefaces 3.5和Mojarra 2.1.14

1 个答案:

答案 0 :(得分:13)

不幸的是,这是“按设计”。 #{}表达式的评估被推迟到访问时间的确切时刻。它们与JSP 中的“标准”EL ${}不同,而不是在标记处理程序解析它们的时刻进行评估,并在同一请求/视图中“缓存”以供将来访问。在呈现<p:outputLabel>时,需要评估#{cc.attrs.required}引用的UIInput#isRequired(),EL上下文中没有任何#{cc}的方法。所以它的任何属性都不会评估任何东西。只有当您坐在<cc:implementation>内时,#{cc}才能在EL上下文中使用,因此其所有属性都将成功评估。

从技术上讲,这是<p:outputLabel>设计中一个不幸的角落案件疏忽。标准JSF和EL表现为指定的行为。基本上,标签星号的显示取决于输入的required属性,应该反过来评估:当复合体内的<p:inputText>被渲染时,或者甚至已经是它的时候建成。因此,标签组件不应询问输入组件是否需要,但输入组件应以某种方式通知标签组件它是否需要。这反过来又变得艰难而且笨拙(因而效率低下)。

如果将标签移动到复合材料内部不是一个选项,那么最好的办法是在输入组件周围创建一个标签文件而不是复合组件。它只需要一些额外的XML样板。

/WEB-INF/tags/input.xhtml

<ui:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:p="http://primefaces.org/ui"
>
    <c:set var="id" value="#{not empty id ? id : 'myInput'}" />
    <c:set var="required" value="#{not empty required and required}" />

    <p:inputText id="#{id}" required="#{required}"/>
</ui:composition>

/WEB-INF/my.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0"
>
    <namespace>http://example.com/my</namespace>

    <tag>
        <tag-name>input</tag-name>
        <source>tags/input.xhtml</source>
    </tag>
</facelet-taglib>

/WEB-INF/web.xml

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/my.taglib.xml</param-value>
</context-param>

用法:

<html ... xmlns:my="http://example.com/my">
...
<p:outputLabel for="myInput" value="#{resources['myLabel']}:" />
<my:input id="myInput" required="#{myBean.required}" />

我刚做了一个快速测试,它对我来说很好。

另见: