c:forEach vs ui:repeat in Facelets

Posted by Roger Keays, 7 June 2007, 12:28 PM

This is probably one of the most frequently asked questions on the Facelets mailing list. Why doesn't my c:forEach tag work correctly? Unfortunately, there are may ways to misuse the jstl tags available in Facelets, so the answer isn't always simple. Here is an explanation of the differences between c:forEach and ui:repeat, along with some examples which will hopefully save you some headaches.

TagHandlers vs Components

The most important thing to understand about the jstl tags in Facelets is that they do not represent components and never become a part of the component tree once the view has been built. Rather, they are tags which are actually responsible for building the tree in the first place. Once they have done their job they expire, are no more, cease to be, etc etc.

Here is a table of the semantics of several common tags. I just discovered, reading the Facelets code, that validators and converters are classified separately. I had always thought they were just tag handlers, but I imagine they behave in much the same way.

TagHandlers
Components
Other

c:forEach
c:choose
c:set
c:if
f:facet
f:actionListener
f:valueChangeListener
ui:include
ui:decorate
ui:composition
any custom tag file

ui:repeat
ui:fragment
ui:component
f:view
f:verbatim
f:selectItems
h:inputText
h:datatable
any custom UIComponent

f:validator
f:converter

One of the problems here is that there is no naming convention to indicate which tags correspond to which constructs. You've just got to know, or find out.

When is the view built?

Now that you understand that tag handlers are only effective when the tree is built, the next logical question should be well, when is tree built?

The short answer is that a new view is built for every request which is not a postback. During a postback, the view is reconstructed from saved state. Quite confusing, and not very obvious I know, but there you have it.

Common laments

The most common pitfalls are either with the JSF lifecycle, EL evaluation or combining tag handlers with components.

My c:if always evaluates to false

<h:dataTable values="${numbers}" var="number">
<h:column>
<c:if test="${number > 5}">
<h:outputText value="${number}"/>
</c:if>
</h:column>
</h:datatable>

Yes, the c:if is always evaluating to false! But it is only ever evaluated once - when the tree is built. The h:outputText component never makes it into the tree. Solution: replace the c:if with:

<ui:fragment rendered="${number > 5}"> ... </ui:fragment>

You could also use the rendered attribute on the h:outputText component in this example.

My ui:include fails inside ui:repeat

<ui:repeat value="#{bean.items}" var="item">
   <ui:include src="#{item.src}"/>
</ui:repeat>

The EL for the ui:include is evaluated when the view is built and is invalid since it relies on a variable only made available by the ui:repeat during rendering. Use c:forEach in this case.

My recursive tag never stops

myTag.xhtml:
<ul>
<ui:repeat value="${item.children} var="child">
<li><eg:myTag item="${child}"/></li>
</ui:repeat>
</ul>

The stop condition in this recursion is supposed to be when you run out of children. The problem is that the custom eg:myTag is just a tag handler, like a special version of ui:include. When the view is built, the ui:repeat has no influence on the building process and can't stop the recursion. Use c:forEach here instead of ui:repeat. Or better still, convert your tag file to a real UIComponent.

You might also recognise that the ${child} EL expression is meaningless during build time in this example, unless you use c:foreach.

My list doesn't change size after deleting or adding an item

<h:form>
<c:forEach items="${list}" var="item">
<h:outputText value="${item.name}"/><br/>
</c:forEach>
<h:commandButton value="Create new item" action="..."/>
<h:commandButton value="Delete an item" action="..."/>
</h:form>

When your view was built you only had, say, 5 items. If you post back to this view and add or delete an item, your view still has 5 h:outputText components in it since it was restored from saved state. In this simple case, you should use ui:repeat and your tree will always contain one h:ouputText component which is iterated over with differing values of ${item}.

If you rely on using c:forEach to dynamically include different form components you could run into difficulty. Always try to think about what the resulting tree looks like and remember it doesn't change on a postback.

Suggestions for the future

Probably the best relief to this problem would be to come up with a better syntax or naming convention to distinguish between tag handlers and components. I imagine you could also improve compilation performance if you did this.

Secondly, we need better terminology. I've used the terms tag handler and component in this blog which isn't too bad. The Facelets' FAQ [1] uses the terms build-time tags and render-time tags which is a bit misleading because render-time tags (components) are involved in all phases of the JSF lifecycle, not just the Render View phase.

Whatever happens, tag handlers are very useful (would you use facelets without ui:decorate?) so let's not get rid of them.

References

[1] http://wiki.java.net/.../FaceletsFAQ#Why_doesn_t_my_c_if_ui_repeat_ui

Comment posted by: Mike Kienenberger on 8 June 2007, 2:25 AM

And, as you mentioned, validators and converters are another story.   For instance, we just had an issue show up on the MyFaces user mailing list because the jsf core converters only evaluate their el expressions on creation, not during any other time.   So making a jsf core converter value binding depend on a component iterator (dataTable, ui:repeat, etc) is impossible.

Comment posted by: Adam Winer on 8 June 2007, 2:45 AM

f:actionListener f:valueChangeListener ... should really go in the "Components" category. In each of these cases, they do have representations of some sort in the produced UIComponent tree. They're just not UIComponents. In particular, what's important here is that EL bindings on actionListener or valueChangeListener are evaluated at component execution time, not tree creation. So, arguably those two really belong in the "components" category.

Comment posted by: Adam Winer on 8 June 2007, 2:46 AM

With regard to Mike's comment: not all converters/validators work the same way as the JSF Core converters/validators. All the Trinidad converters/validators run at component time, so they are free to depend on a component iterator.

Comment posted by: John on 8 July 2007, 1:00 PM

Very well written article. Thanks.

Comment posted by: Ed on 23 July 2007, 10:12 AM

So, does any of this go away with JSF1.2 which promises better integration of JSTL and JSF?

Comment posted by: Roger Keays on 23 July 2007, 1:25 PM

Hi Ed. JSF 1.2 has better integration of JSTL and JSP. This article is specific to Facelets which works just the same on JSF 1.1 and JSF 1.2, so everything here applies to both versions.

Comment posted by: Ed on 23 July 2007, 10:56 PM

Thank you for your reply. I guess I am referring to the Unified Expression Language, which introduces deferred evaluations to EL (evaluation during the JSF lifecyle). See http://java.sun.com/products/jsp/reference/techart/unifiedEL.html. That seems to alter the distinction you are making somewhat, since c:forEach, for example, is still a tag handler but will integrate with components. What's interesting about your article is that even some native facelets tags act as tag-handlers. This has certainly not been well-documented until now.

Comment posted by: Roger Keays on 23 July 2007, 11:28 PM

Facelets treats both deferred and immediate EL expressions the same (deferred according to the definitions on that page). Using the #{} notation with c:forEach doesn't imply that the expression is evaluated at any specific time. In fact, in the case of c:forEach, expressions are evaluated whenever they are referenced, which can also trip you up sometimes. For example, if you had

<c:forEach items="#{dao.query}" var="item"> ... </c:forEach>

Every evaluation of #{item} is rewritten to #{dao.query[x]} and reevaluated, possibly leading to poor performance (blog about this coming soon ). It is all still done during build time though and never actually 'integrates with components'. Apparently the JSP version is different (?).

The performance hit due to reevaluation doesn't apply for ui:repeat because that component is written to store it's value locally. But even components can evaluate their value attribute several times during the lifecycle... it's really up to the author of the component.

Comment posted by: Eric on 14 August 2007, 9:49 PM

For newbies (like me) it would help if someone could add examples of what pages with these types of problems look like. All the textual discussion about the mechanics of what's going on is important, but there's nothing like picture to make things obvious.

Comment posted by: Erik Persson on 21 September 2007, 7:20 AM

Glad to have found this page. We were struggling with the "My ui:include fails inside ui:repeat" issue described here. Re-writing it to use c:forEach seems to have resolved the issue, but has resulted in performance problems, perhaps just as described by "roger" on 23 July 2007. We have made extensive use of the component architecture using ui:include and ui:decorate. Unfortunately these are frequently used in the context of a loop, with the templates being nested a few levels deep. Based on my limited understanding of the situation, we can only re-use these template components inside a loop via the forEach style loop with the associated run-time costs. There does not appear to be any re-usable faclet components which can be used inside of the ui:repeat loop. Is this a correct (if somewhat simplistic) summary of the situation? Can anyone point me to a re-use template pattern using Facelets that works with ui:repeat? As it stands we appear to be in a situation where we have to live with very poor performance or we must give up the nice re-use that we have in place. I would be happy to provide more concrete examples if anyone has input or suggestions.

Comment posted by: Roger Keays on 21 September 2007, 8:22 AM

You can use an ui:include inside ui:repeat, but it is only included once, in a similar way to JSP's <%@ include %> directive. The problems arise when you want a dynamic include which changes for every iteration of the loop. You must use c:forEach in this case.

Comment posted by: Nacho on 9 October 2007, 8:19 PM

Thank you very much for this guide!!!

Comment posted by: hanafey on 17 October 2007, 4:13 AM

<ui:fragment rendered="${number > 5}"> ... </ui:fragment>

no longer appears to be a viable suggestion because "rendered" is no longer a valid attribute.

"c:forEach" does not seem to work with "ui:include" either. The code below produces a stack trace:


<c:forEach var="x" items="#{mainToolBar.include}">
<ui:include src="#{x}"/>
<c:forEach/>

Comment posted by: Dipendra Pokhrel on 6 December 2007, 1:14 PM

c:forEach in jsp supports varstatus with index count and it also supports key/value for map type. for e.g

<c:forEach var='item' items='${map}' varStatus="status">
     <c:out value="${item.key}" /><c:out value="${item.value}"

  <

</c:forEach>

Comment posted by: Dipendra Pokhrel on 6 December 2007, 1:22 PM

Sorry, previous post are mistkenly added. Please ask for confirmation on pressing enter. Ajax is good but, confirmation allows user to  fix/correct the message.

Here is my question:

<c:forEach> in jsp's jstl supports varStatus with index count and it also supports key/value for map type. for e.g

<c:forEach var='item' items='${map}' varStatus="status">
     <c:out value="${item.key}" /><c:out value="${item.value}"

  <c:if test="${status.index}" >
  </c:if>

</c:forEach>

I need to do same using UI:repeat. I found that UI:repeat iterates perfectly but does not provide us the index var as well as key/value for map item.
Please help.

Comment posted by: Roger Keays on 25 January 2008, 9:03 PM

I think Tomahawk's t:dataList will do that for you.

Comment posted by: Rouche on 7 March 2008, 12:36 AM

Im new to Facelets, ive been able to make a menu working but it seems like the recursive nature of my facelet makes the evaluation stack grow to stellar size. Ive been working on this since one week without success.

leftmenu.xhtml (This is the initiate call, the navigationMenu is inside a spring config)

        <t:div id="left_menu">
            <mytag:menu menuItems="#{navigationMenu.navigationItems}"/>
        </t:div>

fragment menu.xhtml

    <ul class="#{styleClass}">
    <c:forEach var="item" items="#{menuItems}">
        <c:choose>
            <c:when test="#{item.open}">
                <li class="ouvert"><a href="#">#{item.label}</a></li>
                <mytag:menu menuItems="#{item.navigationItems}" styleClass="submenu"/>
            </c:when>
            <c:otherwise>
                <li><a href="#{facesContext.externalContext.requestContextPath}#{item.action}.iface">#{item.label}</a></li>
            </c:otherwise>                           
        </c:choose>
    </c:forEach>
    </ul>
I really hope there is a solution to this, i caint think this is not possible.

Comment posted by: Roger Keays on 7 March 2008, 9:08 AM

Hey Rouche, your code looks good to me. I've done exactly the same thing before. FWIW, you might be better off coding this one as a Java UIComponent. It is quite simple and you will get much better performance.

Comment posted by: Rouche on 8 March 2008, 5:56 AM

Yeah thats what i wanted to do. Problem is by architechtural choice, we are not allowed.

After further investigation, my root call <mytag:menu get called 37 times and it stop growing. This is so weird, and wrong in every way, but at least, it doesn't do a stack overflow :)

Comment posted by: Andrew on 20 March 2008, 12:44 AM

Another resource on the subject:

andrewfacelets.blogspot.com/2008/03/build-time-vs-render-time.html

Comment posted by: Zel branco on 27 March 2008, 12:08 PM

I dont understand why do you use facelets and use a "new weird xml language".Yeah .. sure ...it looks elegant..  But at what cost..confusion.. debugging issues..

The problem is Java guy keep on inventing framework one after another..

Instead of focussing on providing GOOD GUI IDE(like in .net)..

.NET does not use this weird XHTML and "new tag language"

Comment posted by: Olisan on 19 April 2008, 4:04 AM

If java wasn't inventing framework one after the other, .NET would not have nHibernate, nUnit, and so on ... So keep your comments to yourself

Comment posted by: guy stevens on 2 July 2008, 6:26 AM

 

Related info: http://wiki.java.net/bin/view/Projects/FaceletsFAQ#Why_doesn_t_my_c_if_ui_repeat_ui

http://andrewfacelets.blogspot.com/2008/03/build-time-vs-render-time.html

Comment posted by: Ivan on 29 October 2008, 7:33 AM

Thanks for the post.  Just cleared up the if statement gotcha for us.

I agree on the confusing aspect of this.  Facelets should have a "gotchas" page.  The fact facelets has core tags is very enticing in terms of its adoption.  It's disappointing when it doesn't behave like we expect, no matter what the reason.

Classic rule of least surprise.

Comment posted by: hasibul on 6 November 2008, 9:27 PM

nice site

Comment posted by: hasibul on 6 November 2008, 9:28 PM

Does <c:forEach> can be used in XHTML?

Comment posted by: Bob on 4 December 2008, 11:35 AM

Stupendous!  Dynamite!  Superb!  Spectacular!  FANTASTIC!  MARVELOUS!

Comment posted by: Roger Keays on 8 December 2008, 3:14 AM

not super?

Comment posted by: Vlad on 10 December 2008, 6:28 PM

JSF 2.0 (with Facelets within) goes further in confusing developers.

Personally I consider mixing expression with different execution time in one context as a bad design, which is innate nature of facelets and JSF. JSF is sophisticated framework, what means its design is too complicated for static HTML (and a source of unacceptable overhead) and is not ready for dynamic Web.

JSF suxx. Try to get rid of it. As it said Java community is in demand of the next brand new framework.

 

Add a comment

Please visit http://www.ilikespam.com/blog/c%3Aforeach-vs-ui%3Arepeat-in-facelets to add your comments.