Como programadores especializados en uno o varios lenguajes o frameworks, en ocasiones utilizamos características que no forman parte de la documentación oficial. En esta oportunidad haré alusión a un elemento en Facelets, el atributo rendered de la etiqueta o tag ui:fragment.
La etiqueta ui:fragment
El tag ui:fragment es utilizado para delimitar un conjunto de componentes en función es similar al elemento ui:component, con la salvedad que no elimina el código que existe alrededor de él.
La documentación oficial indica que esta etiqueta sólo posee dos atributos (id y binding); sin embargo en varios artículos se indica la existencia de un atributo adicional, rendered, que hace posible que se muestren o no los componentes dependiendo de un valor condicional. En el siguiente ejemplo se muestra un fragmento de código donde aparece este atributo:
<ui:fragment rendered="#{condition}">
<h:outputText value="text 1"/>
<h:outputText value="text 2"/>
<h:outputText value="text 3"/>
</ui:fragment>
¿Cómo es posible que rendered si funcione a pesar de no estar documentado? La razón en realidad es muy simple: los componentes JSF se insertan dentro de un árbol y como tales heredan las propiedades de su componente padre. Por lo tanto, esta excepción funciona porque los componentes hijos heredan el atributo rendered en ui:fragment.
¿Pero si funciona porque busco alternativas?
Los IDEs como NetBeans y Eclipse ya soportan en sus últimas versiones los tags de Facelets y JSF. Estos IDEs resaltan todo texto que no se encuentre conforme a la especificación oficial, y marcaba el código anterior como si se tratase de un error. Es por esta razón que decidí hacer una búsqueda de alternativas para conseguir el mismo resultado.
Entre las alternativas conocidas para esta situación se pueden señalar:
1. Usar otras estructuras agrupadoras:
<s:div rendered="#{condition}">
<h:outputText value="text 1"/>
<h:outputText value="text 2"/>
<h:outputText value="text 3"/>
</s:div>
<s:fragment rendered="#{condition}">
<h:outputText value="text 1"/>
<h:outputText value="text 2"/>
<h:outputText value="text 3"/>
</s:fragment>
Los tags s:div y s:fragment pertenecen a la librería de tags que provee Seam (http://docs.jboss.org/seam/2.2.1.CR2/reference/en-US/html/controls.html) y son estructuras que agrupan componentes, en el caso de s:div se muestra el contenido dentro de un div mientras que s:fragment es una estructura invisible.
Otra estructura que se puede usar es:
<h:panelGroup rendered="#{condition}">
<h:outputText value="text 1"/>
<h:outputText value="text 2"/>
<h:outputText value="text 3"/>
</h:panelGroup>
Si al panel group no se le especifica el valor para id, style o styleClass funciona como entidad agrupada transparente (en caso se le asigne algún valor los componentes se muestran dentro de un span)
2. Usar verbatim si es que el contenido es sólo texto (aunque esto a la larga no es práctico para la mayoría de ocasiones)
<f:verbatim rendered="#{condition}">
text 1
text 2
text 3
</f:verbatim>
3. Poner el atributo rendered a cada uno de los elementos hijos:
<h:outputText value="text 1" rendered="#{condition}"/>
<h:outputText value="text 2" rendered="#{condition}"/>
<h:outputText value="text 3" rendered="#{condition}"/>
Con estas tres opciones es posible generar código válido para la versión de JSF 1.2 y no estar dependiendo de ui:fragment como elemento contenedor.