Primefaces outputLabel dla komponentu kompozytowego

Mam problem z używaniem p:outputLabel gdy jest używany z komponentem kompozytowym. Mam komponent złożony z polem p:inputText (usunąłem nieistotne części z komponentu):

<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>

Teraz nie będę używał tego komponentu z p:outputLabel:

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

Wszystko działa dobrze, wymagana Walidacja, wyświetlany jest również komunikat, ale nie ma * sign on label, tak jak jest, gdy podłączam label bezpośrednio do komponentu p:inputText. Jeśli z drugiej strony, hardcode required="true" na p:inputText Wszystko działa dobrze.

Debugowałem org.primefaces.component.outputlabel.OutputLabelRenderer i odkryłem, że komponent jest rozpoznawany jako UIInput, Ale input.isRequired() zwraca false. Następnie odkryto, że atrybut required nie jest jeszcze zdefiniowany na komponencie, więc zwraca {[14] } jako wartość domyślną i UIInput:

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

Również, jeśli po prostu przenieść p:outputLabel wewnątrz komponentu kompozytowego wszystko działa dobrze. Jak EL jest oceniany później wewnątrz komponentu kompozytowego?

Używam Primefaces 3.5 z Mojarra 2.1.14

Author: partlov, 2013-02-21

1 answers

To jest, niestety, "z założenia". Ocena wyrażeń #{} jest odroczona do dokładnego momentu dostępu. Są one w przeciwieństwie do "standardowego" EL ${} w JSP , a nie ocenianego dokładnie w momencie, gdy są przetwarzane przez obsługę znaczników i "buforowane" dla przyszłego dostępu podczas tego samego żądania/widoku. W chwili, gdy <p:outputLabel> jest renderowane, a zatem #{cc.attrs.required} jako odwołanie przez UIInput#isRequired() musi zostać ocenione, nie ma żadnego #{cc} w kontekście EL. Więc każdy z jego atrybuty nie oceniałyby niczego. Tylko wtedy, gdy siedzisz wewnątrz <cc:implementation>, {[9] } jest dostępny w kontekście EL i wszystkie jego atrybuty będą w ten sposób pomyślnie oceniane.

Technicznie rzecz biorąc, jest to niefortunny przypadek w projektowaniu <p:outputLabel>. Standardowe JSF i EL zachowują się zgodnie z opisem. Zasadniczo, prezentacja gwiazdki etykiety w zależności od atrybutu required wejścia powinna być oceniana odwrotnie: w tej chwili <p:inputText> wewnątrz kompozytu ma być renderowany, a może nawet już wtedy, gdy ma być zbudowany. Tak więc komponent label nie powinien pytać komponentu wejściowego, czy jest wymagany, ale komponent wejściowy powinien w jakiś sposób powiadomić komponent label, że jest wymagany. To zaś jest trudne i niezdarne (a stąd nieefektywne) do wdrożenia.

Jeśli przeniesienie etykiety do wnętrza kompozycji nie jest możliwe, najlepszym rozwiązaniem jest utworzenie pliku znacznika zamiast komponentu kompozytowego wokół wejścia komponent. Wymaga tylko dodatkowego kotła 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>

Użycie:

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

Zrobiłem szybki test i działa dobrze dla mnie.

Zobacz też:

 13
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:32:08