Comment faire une grille de composant composite JSF?

j'ai beaucoup de outputLabel et inputText paires dans 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>

je veux avoir un comportement pour chacun d'eux: comme la même validation ou la même taille pour chaque texte entré. J'ai donc créé un composant composite qui ne comprend qu'un outputLabel et un inputText

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

mais maintenant quand je les mets dans un gridPanel, ils ne sont pas alignés en fonction de la longueur du texte de l'étiquette. Je comprends pourquoi, mais je n'ai pas savoir comment les contourner.

22
demandé sur Anatoli 2011-04-19 12:39:03

2 réponses

un composant composite est effectivement rendu comme un seul composant. Vous voulez utiliser un fichier D'étiquette Facelet à la place. Il est rendu exactement comme sa sortie le rend. Voici un exemple de coup d'envoi en supposant que vous voulez un formulaire de 3 colonnes avec un champ de message dans la troisième colonne.

crée le fichier d'étiquette dans /WEB-INF/tags/input.xhtml (ou dans /META-INF quand vous voulez fournir des étiquettes dans un fichier JAR qui doit être inclus dans /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>

définissez-le dans /WEB-INF/example.taglib.xml (ou dans /META-INF lorsque vous voulez fournir des étiquettes dans un fichier JAR qui doit être inclus dans /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>

déclare l'usage de taglib dans /WEB-INF/web.xml (ceci n'est pas nécessaire lorsque les tags sont fournis par un fichier JAR qui est inclus dans /WEB-INF/lib ! JSF chargera automatiquement tous les fichiers *.taglib.xml de /META-INF ).

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

(plusieurs fichiers taglib peuvent être séparés par point-virgule ; )

enfin il suffit de le déclarer dans les gabarits de votre page principale.

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

(le #{bean.countries} doit retourner un Map<String, String> avec les codes de pays comme clés et les noms de pays comme valeurs)

Capture d'écran:

enter image description here

Espérons que cette aide.

44
répondu BalusC 2016-04-28 07:09:58

il aurait dû y avoir un commutateur dans panelGrid pour rendre les composants composites séparément. J'ai une solution pour ce. Vous pouvez avoir des composants composites séparés au lieu de les assembler. Dans chaque composant composite vous pouvez utiliser l'ui:fragments pour délimiter les composants que vous voulez séparément tomber sous des colonnes différentes. Qui suit est extrait de mon inputText.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>

maintenant cela ne va pas s'aligner dans la forme qui est à l'intérieur de la 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>

donc j'ai étendu la méthode encodeRecursive de GroupRenderer, pour ajouter après étiquette et un champ avant:

// 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
répondu Anichak 2011-09-17 06:13:05