首页 文章

Primefaces outputLabel用于复合组件

提问于
浏览
11

当与复合组件一起使用时,我遇到使用 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 组件时 . 另一方面,如果我在 p:inputText 上硬编码 required="true" 一切正常 .

我通过 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 回答

  • 13

    不幸的是,这是"by design" . #{} 表达式的评估被推迟到访问时间的确切时刻 . 它们与JSP中的"standard" EL ${} 不同,它们在标记处理程序和"cached"解析的确切时刻进行评估,以便在同一请求/视图期间进行访问 . 在渲染 <p:outputLabel> 的那一刻,因此 UIInput#isRequired() 引用的 #{cc.attrs.required} 需要被评估,在EL上下文中没有任何 #{cc} 的方法 . 所以它的任何属性都不会评估任何东西 . 只有当你坐在 <cc:implementation> 内时, #{cc} 才能在EL上下文中使用,因此它的所有属性都会成功评估 .

    从技术上讲,这是 <p:outputLabel> 设计中一个不幸的角落案件疏忽 . 标准JSF和EL表现为指定的行为 . 基本上,标签's asterisk depending on the input' s 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}" />
    

    我只是做了一个快速测试,它对我来说很好 .

    另见:

相关问题