Направляющая поверхностьLabel для составного компонента

У меня проблема с использованием 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. Если я, с другой стороны, hardcode required="true" на p:inputText, все работает нормально.

Я отлаживал org.primefaces.component.outputlabel.OutputLabelRenderer и обнаружил, что этот компонент распознан как UIInput, но input.isRequired() возвращает false. Дальнейшая отладка обнаружила, что атрибут required еще не определен на компоненте, поэтому он возвращает false как значение по умолчанию я UIInput:

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

Кроме того, если я просто перемещаю p:outputLabel внутри составного компонента, все работает нормально. Как EL оценивается позже в составном компоненте?

Я использую Primefaces 3.5 с Mojarra 2.1.14

Ответы

Ответ 1

Это, к сожалению, "по дизайну". Оценка выражений #{} откладывается до момента момента доступа. Они не похожи на "стандартные" EL ${} в JSP, которые не оцениваются в тот момент, когда они были проанализированы обработчиком тегов и "кэшированы" для будущего доступа во время одного и того же запроса/представления. В настоящий момент отображается <p:outputLabel>, и, следовательно, #{cc.attrs.required}, как указано UIInput#isRequired(), необходимо оценить, нет никаких средств в #{cc} в контексте EL. Таким образом, любой из его атрибутов ничего не оценил бы. Только когда вы сидите внутри <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}" />

Я просто сделал быстрый тест, и он отлично работает для меня.

См. также: