wutzebaer
wutzebaer

Reputation: 14863

c:forEach runs always the same amount of loops

hi i'm trying to display a tree structure in JSF

for intendation i want to insert

<span class="intendWidth" />

this is my jsf-code

<ui:repeat value="#{myHandler.entityTree}" var="entityDepthHolder">
    <p:commandLink action="#{myHandler.toggle(entityDepthHolder.entity)}">
        <div>
            <c:forEach begin="0" end="#{entityDepthHolder.depth}">
                <span class="intendWidth" />
            </c:forEach>
            #{entityDepthHolder.depth} #{entityDepthHolder.entity.title}
        </div>
    </p:commandLink>
</ui:repeat>

but for some reason the c:forEach always run once, although only one entityDepthHolder.depth is 1, all others are 0

any ideas how to insert a tag n-times without c:forEach?

Upvotes: 2

Views: 301

Answers (1)

BalusC
BalusC

Reputation: 1108642

The <c:forEach> runs during view build time (that moment when XHTML is turned into JSF component tree), while the <ui:repeat> runs during view render time (that moment when JSF component tree produces HTML output).

So, when the <c:forEach> runs, the #{entityDepthHolder} is nowhere available in the EL scope and evaluates to null and in this case implicitly coerced to 0. As the begin is also 0 and the end is inclusive, you effectively end up with 1 item.

After the view build time, the JSF component tree ends up like this:

<ui:repeat value="#{myHandler.entityTree}" var="entityDepthHolder">
    <p:commandLink action="#{myHandler.toggle(entityDepthHolder.entity)}">
        <div>
            <span class="intendWidth" />
            #{entityDepthHolder.depth} #{entityDepthHolder.entity.title}
        </div>
    </p:commandLink>
</ui:repeat>

And during view render time, the very same HTML is repeatedly generated.

You've 2 options to fix this:

  1. Use <c:forEach> instead of <ui:repeat> on the outer loop. Caveat is, this breaks view scoped beans in Mojarra versions older than 2.1.18.

  2. Use <ui:repeat> instead of <c:forEach> on the inner loop. If you happen to use JSF utility library OmniFaces, then you may find the #{of:createArray()} function helpful in this.

    <ui:repeat value="#{of:createArray(entityDepthHolder.depth)}">
    

See also:

Upvotes: 5

Related Questions