Search code examples
jsfdatatablerichfacescomposite-component

How to create a composite component for a datatable column?


Given this datatable (naturally working):

<rich:dataTable var="var" value="#{values}">
<rich:column>
  <f:facet name="header">
   HEADER
  </f:facet>
  <h:outputText value="#{var}" />
</rich:column>
</rich:dataTable>

If I define a custom component (also ok in the syntax and at the right place under resources/components):

   <?xml version="1.0" encoding="UTF-8"?>
    <html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:a4j="http://richfaces.org/a4j"
        xmlns:rich="http://richfaces.org/rich"
        xmlns:composite="http://java.sun.com/jsf/composite">

    <!-- INTERFACE -->
    <composite:interface>
        <composite:attribute name="val" />
    </composite:interface>

    <!-- IMPLEMENTATION -->
    <composite:implementation>
        <rich:column>
            <f:facet name="header">
       HEADER
       </f:facet>
       <h:outputText value="#{cc.attrs.val}" />
       </rich:column>
    </composite:implementation>
    </html>

Why does the following does not work?

<?xml version="1.0" encoding="UTF-8"?>
<ui:composition template="/WEB-INF/templates/default.xhtml"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich"
    xmlns:my="http://java.sun.com/jsf/composite/components">
    <ui:define name="content">
        <rich:dataTable var="var" value="#{values}">
                 <my:mycolumn val="#{var}"/>
                </rich:dataTable>
    </ui:define>
</ui:composition>

Do you know how could I let it work (I want to define my own column and save code)? Thanks a lot! Bye


Solution

  • The <my:mycolumn> element must be an instance of UIColumn as that's the only valid child of a UIData component during the render response phase. All other UIComponent types will be ignored, thus not rendered. A composite component is implicitly a UINamingContaner component, which isn't a UIColumn and therefore ignored.

    A PrimeFaces <p:dataTable> with a backing component that extends UIColumn also won't work due to the wrong lifecycle of a composite component. The column has to be created during the view build time, while the composite component's body is created during view render time.

    The solution is to create a tag file instead, which means an extra .taglib.xml file, yet it works flawlessly.

    /WEB-INF/tags/column.xhtml:

    <ui:composition
        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:rich="http://richfaces.org/rich">
        <rich:column>
            <f:facet name="header">HEADER</f:facet>
            <h:outputText value="#{val}" />
        </rich:column>
    </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>column</tag-name>
            <source>tags/column.xhtml</source>
            <attribute>
                <description>Column value</description>
                <name>val</name>
            </attribute>
        </tag>
    </facelet-taglib>
    

    Note: The <attribute> entries are not mandatory, but are nice for documentation purposes, such as generated docs and IDE autocomplete.

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

    Usage:

    <ui:composition
        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:rich="http://richfaces.org/rich"
        xmlns:my="http://example.com/my">
        <rich:dataTable value="#{values}" var="value">
            <my:column val="#{value}" />
        </rich:dataTable>
    </ui:composition>