Jak zrobić siatkę komponentu kompozytowego JSF?

Mam wiele par outputLabel i inputText w panelGrids

<h:panelGrid columns="2">
  <h:outputLabel value="label1" for="inputId1"/>
  <h:inputText id="inputId1/>

  <h:outputLabel value="label2" for="inputId2"/>
  <h:inputText id="inputId2/>

  ...
</h:panelGrid>

Chcę mieć pewne zachowanie dla wszystkich z nich: jak ta sama Walidacja lub ten sam rozmiar dla każdego tekstu wejściowego. Dlatego stworzyłem komponent złożony, który zawiera tylko outputLabel i inputText

<my:editField value="field1"/>
<my:editField value="field2"/>

Ale teraz, kiedy umieszczam je w gridpanelu, nie są wyrównywane w zależności od długości tekstu etykiety. Rozumiem dlaczego, ale nie wiem jak to obejść.

Author: Anatoli, 2011-04-19

2 answers

Komponent złożony jest renderowany jako pojedynczy komponent. Zamiast tego chcesz użyć pliku znacznika Facelet. Jest renderowany dokładnie tak, jak to, co renderuje jego wyjście. Oto przykład kickoff zakładając, że chcesz formularz 3-kolumnowy z polem wiadomości w trzeciej kolumnie.

Utwórz plik znacznika w /WEB-INF/tags/input.xhtml (lub w /META-INF, Gdy chcesz podać znaczniki w pliku JAR, który ma być zawarty w /WEB-INF/lib).

<ui:composition
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

    <c:set var="id" value="#{not empty id ? id : (not empty property ? property : action)}" />
    <c:set var="required" value="#{not empty required and required}" />

    <c:choose>
        <c:when test="#{type != 'submit'}">
            <h:outputLabel for="#{id}" value="#{label}&#160;#{required ? '*&#160;' : ''}" />
        </c:when>
        <c:otherwise>
            <h:panelGroup />
        </c:otherwise>
    </c:choose>

    <c:choose>
        <c:when test="#{type == 'text'}">
            <h:inputText id="#{id}" value="#{bean[property]}" label="#{label}" required="#{required}">
                <f:ajax event="blur" render="#{id}-message" />
            </h:inputText>
            <h:message id="#{id}-message" for="#{id}" />
        </c:when>
        <c:when test="#{type == 'password'}">
            <h:inputSecret id="#{id}" value="#{bean[property]}" label="#{label}" required="#{required}">
                <f:ajax event="blur" render="#{id}-message" />
            </h:inputSecret>
            <h:message id="#{id}-message" for="#{id}" />
        </c:when>
        <c:when test="#{type == 'select'}">
            <h:selectOneMenu id="#{id}" value="#{bean[property]}" label="#{label}" required="#{required}">
                <f:selectItems value="#{options.entrySet()}" var="entry" itemValue="#{entry.key}" itemLabel="#{entry.value}" />
                <f:ajax event="change" render="#{id}-message" />
            </h:selectOneMenu>
            <h:message id="#{id}-message" for="#{id}" />
        </c:when>
        <c:when test="#{type == 'submit'}">
            <h:commandButton id="#{id}" value="#{label}" action="#{bean[action]}" />
            <h:message id="#{id}-message" for="#{id}" />
        </c:when>
        <c:otherwise>
            <h:panelGroup />
            <h:panelGroup />
        </c:otherwise>            
    </c:choose>
</ui:composition>

Zdefiniuj go w /WEB-INF/example.taglib.xml (lub w /META-INF, Gdy chcesz podać tagi w Plik JAR, który ma być zawarty w /WEB-INF/lib):

<?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/jsf/facelets</namespace>
    <tag>
        <tag-name>input</tag-name>
        <source>tags/input.xhtml</source>
    </tag>
</facelet-taglib>

Zadeklaruj użycie taglib w /WEB-INF/web.xml (nie jest to potrzebne, gdy znaczniki są dostarczane przez plik JAR, który jest zawarty w /WEB-INF/lib! JSF automatycznie załaduje wszystkie *.taglib.xml pliki z /META-INF).

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

(wiele plików taglib może być oddzielonych średnikiem ;)

W końcu wystarczy zadeklarować to w szablonach strony głównej.

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:my="http://example.com/jsf/facelets"
>
    <h:head>
        <title>Facelet tag file demo</title>
    </h:head>
    <h:body>
        <h:form>
            <h:panelGrid columns="3">
                <my:input type="text" label="Username" bean="#{bean}" property="username" required="true" />
                <my:input type="password" label="Password" bean="#{bean}" property="password" required="true" />
                <my:input type="select" label="Country" bean="#{bean}" property="country" options="#{bean.countries}" />
                <my:input type="submit" label="Submit" bean="#{bean}" action="submit" />
            </h:panelGrid>
        </h:form>
    </h:body>
</html>

( #{bean.countries} powinien zwracać {[16] } z kodami krajów jako kluczami i krajem nazwy jako wartości)

Zrzut ekranu:

Tutaj wpisz opis obrazka

Mam nadzieję, że to pomoże.
 44
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
2016-04-28 07:09:58

W panelGrid powinien znajdować się przełącznik do renderowania komponentów kompozytowych oddzielnie. Mam na to rozwiązanie. Możesz mieć oddzielne komponenty kompozytowe zamiast łączyć je ze sobą. W każdym komponencie kompozytowym można użyć UI:fragments, aby rozgraniczyć komponenty, które mają być osobno umieszczone pod różnymi kolumnami. Poniżej znajduje się wyciąg z mojego tekstu wejściowego.xhtml:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:composite="http://java.sun.com/jsf/composite"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<composite:interface>
    <composite:attribute name="id" />
    <composite:attribute name="value" />
    <composite:attribute name="label" />
    <composite:attribute name="readonly" />
    <composite:attribute name="disabled" />
    <composite:attribute name="required" />

</composite:interface>

<composite:implementation>

    <ui:fragment id="label">
        <h:outputText id="#{cc.attrs.id}Label" value="#{cc.attrs.label}"
            for="#{cc.attrs.id}" />
        <h:outputLabel value="#{bundle['label.STAR']}"
            rendered="#{cc.attrs.required}" styleClass="mandatory"
            style="float:left"></h:outputLabel>
        <h:outputLabel value="&nbsp;" rendered="#{!cc.attrs.required}"
            styleClass="mandatory"></h:outputLabel>
    </ui:fragment>
    <ui:fragment id="field">
        <h:inputText id="#{cc.attrs.id}" value="#{cc.attrs.value}"
            styleClass="#{not component.valid ? 'errorFieldHighlight medium' : 'medium'}"
            disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}"
            label="#{cc.attrs.label}" readonly="#{cc.attrs.readonly}">
        </h:inputText>
    </ui:fragment>
</composite:implementation>

</html>

Teraz to nie będzie wyrównać w formie, która jest wewnątrz panelGrid:

<h:panelGrid width="100%">
<my:inputText label="#{bundle['label.fname']}" value="#{bean.fname}" id="fname"></my:inputtext>
<my:inputText label="#{bundle['label.lname']}" value="#{bean.lname}" id="lname"></my:inputtext>
</panelGrid>

Więc ja rozszerzono metodę Enkoderekursywną grupy, aby dodać pole after label i before:

// inside my extended renderer
protected void encodeRecursive(FacesContext context, UIComponent component)
            throws IOException {

        // Render our children recursively
        if (component instanceof ComponentRef
                && component.getId().equals("field")) {
            context.getResponseWriter().startElement("td", component);
        }

        super.encodeRecursive(context, component);
        if (component instanceof ComponentRef
                && component.getId().equals("label")) {
            context.getResponseWriter().endElement("td");
        }
    }
 4
Author: Anichak,
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
2011-09-17 06:13:05