JSF 2 ui:repeat: group every n items inside a div

Distortum picture Distortum · May 7, 2012 · Viewed 13.4k times · Source

Given a collection that I want to arrange on a page like this:

<!-- Group 0 -->
<div style="float:left;">
    <div><!-- Item 0 --></div>
    <div><!-- Item 1 --></div>

    <!-- ... -->

    <div><! -- Item n - 1 --></div>
</div>
<!-- Group 1 -->
<div style="float:left;">
    <div><!-- Item n     --></div>
    <div><!-- Item n + 1 --></div>

    <!-- ... -->

    <div><! -- Item 2n - 1 --></div>
</div>

<!-- ... -->

<!-- Group g -->
    <div><!-- Item gn     --></div>
    <div><!-- Item gn + 1 --></div>

    <!-- ... -->

    <div><! -- Item (g + 1)n - 1 --></div>
</div>

Is there some sort of trick I can use to do this inside a ui:repeat or by some other technique, preferably other than creating a custom component?

Answer

BalusC picture BalusC · May 7, 2012

You can check the current loop round by the varStatus attribute and print the intermediary </div><div style="float: left;"> whenever necessary.

E.g. every 3 items:

<div style="float: left;">
    <ui:repeat value="#{bean.list}" var="item" varStatus="loop">
        <h:outputText value="&lt;/div&gt;&lt;div style='float: left;'&gt;" escape="false" rendered="#{not loop.first and loop.index % 3 == 0}" />
        <div>#{item}</div>
    </ui:repeat>
</div>

Note that it's not possible to wrap this as plain HTML inside a <h:panelGroup>, because it would result in non-wellformed XML, hence the <h:outputText escape="false"> with them as XML entities.


Update as per the comments, here's an alternate approach having the <div>s definied only once which is probably less confusing:

<ui:repeat value="#{bean.list}" var="item" varStatus="loop">
    <h:outputText value="&lt;div style='float: left;'&gt;" escape="false" rendered="#{loop.index % 3 == 0}" />
    <div>#{item}</div>
    <h:outputText value="&lt;/div&gt;" escape="false" rendered="#{loop.last or (loop.index + 1) % 3 == 0}" />
</ui:repeat>