Composite component pitfalls: Root component

In my second post in the JSF composite component pitfalls series I would like to discuss the root component of composite components. This time I will show you examples that are not working although they seem reasonable at first glance.

Whenever a composite component is used in a page JSF inserts a separate root component into the component tree. Normally this is most welcome as it avoids ID clashes if the component is used multiple times. But in some rare cases this leads to unexpected side effects.

I will demonstrate the effect with the composite component inputField which combines an h:outputLabel and an h:inputText component:

<cc:interface>
  <cc:attribute name="value"/>
</cc:interface>
<cc:implementation>
  <h:outputLabel for="input" value="Input:"/>
  <h:inputText id="input" value="#{cc.attrs.value}"/>
</cc:implementation>

In the following examples two of those inputField components are placed in a h:panelGrid component with two columns:

<h:panelGrid columns="2">
  <jl:inputField value="#{testBean.value1}"/>
  <jl:inputField value="#{testBean.value2}"/>
</h:panelGrid>

You might expect that JSF now renders a table with two rows containing a label in the first column and an input field in the second. Unfortunately that is not the case. What JSF actually (and correctly) renders is a table with one row and two columns. As h:panelGrid only “sees” the composite component root components it puts each of them in one cell of the table.

Currently (and this includes JSF 2.2) there is no direct workaround for this problem.

Let’s have a look at another example that is unfortunately not working as expected. The following composite component is intended as a wrapper component for h:column replacing the header facet with a simple attribute:

<cc:interface>
  <cc:attribute name="header"/>
</cc:interface>
<cc:implementation>
  <h:column>
    <f:facet name="header">
      <h:outputText value="#{cc.attrs.header}"/>
    </f:facet>
    <cc:insertChildren/>
  </h:column>
</cc:implementation>

When we use this composite component in a h:dataTable component like in the following code nothing is rendered:

<h:dataTable var="item" value="#{testBean.items}">
  <jl:column header="ID">
    #{item.id}
  </jl:column>
</h:dataTable>

What happens? The data table component expects h:column children but only “sees” the composite component root element. Therefore no column is added to the table.

Again, this is not a bug but the way composite components are designed. I would like to point out that problems like this won’t bother you very often in your daily work with JSF. I use composite components on a regular basis in various projects and basically they work fine and significantly simplify development.

Advertisements

8 responses to “Composite component pitfalls: Root component

  1. Pingback: Composite component pitfalls - Root component - Blog - Irian

  2. Hi Michael, just a side note:
    The desired behaviour can be achieved using custom tags instead of composites.

    Greetings,
    Tom

  3. Hi Tom, you are absolutely right. As always, JSF offers several ways of solving problems. This is one of the cases where a custom tag for a XHTML fragment is still helpful.

  4. You can implement composite component acting like column just using the componentType tag:
    .

    For this, you need to create a class derived from UIColumn implementing NamingContainer interface (required for composite components) and registered as “my.Column” (for example) component using config file or annotations:
    @FacesComponent(“my.Column”)
    public class MyColumn extends UIColumn implements NamingContainer

    You must also use predefined component family for the component:
    public String getFamily()
    {
    return UINamingContainer.COMPONENT_FAMILY; // Important! Required for composite components.
    }

    Another trick is that must not use for the column component (yeah, JSF is a tricky beast). This is an issue of the default column renderer – it handles column children components by itself and isn’t aware enough of composite components internals. So adding will prevent renderring children but ommitting will render them correctly – that is the pitfall.
    By the way, works correctly.

  5. Hi Michael,

    Is it possible to use ui:repeat in a composite component? If not is there a way in the composite component markup or component class that this can be achieved since I have tried to read through the spec to find this out but the spec does not have the 2.2 stuff inside even though it is a final version, weird really.

    Kind regards,
    Mark P Ashworth

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s