2

I have an h:panelGrid with two columns and various rows:

<h:panelGrid columns="2">
    <p:outputLabel for="attr1" value="#{messages.attr1}" />
    <p:inputText id="attr1" value="#{viewBean.attr1}" />
    <p:outputLabel for="attr2" value="#{messages.attr2}" />
    <p:inputText id="attr2" value="#{viewBean.attr2}">
    <p:outputLabel for="attr3" value="#{messages.attr3}" />
    <p:inputText id="attr3" value="#{viewBean.attr3}" />
</h:panelGrid>

Now, some rows should only be present conditionally. In the example this could be the attr2 and attr3. When I build an <ui:fragment /> around them the conditional rendering works (see below), however jsf tries to put the whole block into one <td /> table cell element.

<h:panelGrid columns="2">
    <p:outputLabel for="attr1" value="#{messages.attr1}" />
    <p:inputText id="attr1" value="#{viewBean.attr1}" />
    <ui:fragment rendered="#{viewBean.myCondition}">
        <p:outputLabel for="attr2" value="#{messages.attr2}" />
        <p:inputText id="attr2" value="#{viewBean.attr2}">
        <p:outputLabel for="attr3" value="#{messages.attr3}" />
        <p:inputText id="attr3" value="#{viewBean.attr3}" />
    </ui:fragment>
</h:panelGrid>

Another option would be to create two panelGrids. One for the first block and one for the second block:

<h:panelGrid columns="2">
    <p:outputLabel for="attr1" value="#{messages.attr1}" />
    <p:inputText id="attr1" value="#{viewBean.attr1}" />
</h:panelGrid>
<h:panelGrid columns="2">
    <ui:fragment rendered="#{viewBean.myCondition}">
        <p:outputLabel for="attr2" value="#{messages.attr2}" />
        <p:inputText id="attr2" value="#{viewBean.attr2}">
        <p:outputLabel for="attr3" value="#{messages.attr3}" />
        <p:inputText id="attr3" value="#{viewBean.attr3}" />
    </ui:fragment>
</h:panelGrid>

The problem here is that the columns are now not succinct anymore across both grids. What could be a solution to circumvent this issue?

Note, that I have more than just three rows so putting a rendered attribute for each outputLabel and inputText element would be quite tedious.

schrobe
  • 767
  • 2
  • 8
  • 29

1 Answers1

5

The <h:panelGrid> renderer only considers direct UIComponent children as table cells, not the deeper nested ones. The <ui:fragment> is actually also an UIComponent. Hence it becomes a single table cell with all of its nested children enclosed.

You have 2 options, depending on the source of the rendered condition:

  1. If it's available during view build time, use <c:if> instead.

    <h:panelGrid columns="2">
        <p:outputLabel ... />
        <p:inputText ... />
        <c:if test="#{viewBean.myCondition}">
            <p:outputLabel ... />
            <p:inputText ... />
            <p:outputLabel ... />
            <p:inputText ... />
        </c:if>
    </h:panelGrid>
    
  2. Otherwise, if it's not guaranteed to be available during view build time, get rid of <ui:fragment> and repeat the rendered condition over the children.

    <h:panelGrid columns="2">
        <p:outputLabel ... />
        <p:inputText ... />
        <p:outputLabel ... rendered="#{viewBean.myCondition}" />
        <p:inputText ... rendered="#{viewBean.myCondition}" />
        <p:outputLabel ... rendered="#{viewBean.myCondition}" />
        <p:inputText ... rendered="#{viewBean.myCondition}" />
    </h:panelGrid>
    

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555