validate custom create component attribute jsf jsf-2 grid alignment composite-component

custom - jsf composite component



¿Cómo hacer una grilla del componente compuesto JSF? (2)

Tengo muchos de los pares outputLabel y inputText en 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>

Quiero tener un comportamiento para todos ellos: como la misma validación o el mismo tamaño para cada texto de entrada. Así que he creado un componente compuesto que solo incluye un outputLabel y un inputText

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

Pero ahora cuando los pongo en un gridPanel, no se alinean según la longitud del texto de la etiqueta. Entiendo por qué, pero no sé cómo evitarlo.


Debería haber un interruptor en panelGrid para representar componentes compuestos por separado. Tengo una solución para esto. Puede tener componentes compuestos separados en lugar de agruparlos. En cada componente compuesto, puede usar ui: fragments para delimitar los componentes que desea incluir por separado en columnas diferentes. Lo siguiente es extracto de mi 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>

Ahora, esto no va a alinearse en el formulario que está dentro de 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>

Así que extendí el método encodeRecursive de GroupRenderer para agregar después de la etiqueta y un campo anterior:

// 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"); } }


Un componente compuesto realmente se representa como un componente único. En su lugar, quiere usar un archivo de etiqueta Facelet. Se renderiza exactamente como lo que sea que rinda su salida. Este es un ejemplo inicial, suponiendo que desea un formulario de 3 columnas con un campo de mensaje en la tercera columna.

Cree el archivo de etiqueta en /WEB-INF/tags/input.xhtml (o en /META-INF cuando desee proporcionar etiquetas en un archivo JAR que se incluirá en /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>

/WEB-INF/example.taglib.xml en /WEB-INF/example.taglib.xml (o en /META-INF cuando desee proporcionar etiquetas en un archivo JAR que se incluirá en /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>

Declare el uso de taglib en /WEB-INF/web.xml (esto no es necesario cuando las etiquetas son proporcionadas por un archivo JAR que se incluye en /WEB-INF/lib ! JSF cargará automáticamente todos los archivos *.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>

(múltiples archivos taglib se pueden separar por punto ; coma ; )

Finalmente solo declarelo en sus plantillas de página principal.

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

(el #{bean.countries} debería devolver un Map<String, String> con códigos de país como claves y nombres de países como valores)

Captura de pantalla:

Espero que esto ayude.