Patterns in Software

JSF c:forEach vs ui:repeat

By , 7 June 2007

JSF c:forEach vs ui:repeat

This is probably one of the most frequently asked questions on the JSF mailing list. Why doesn't my c:forEach tag work correctly? Unfortunately, there are may ways to misuse the JSTL tags available in JSF, 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.

JSF c:forEach vs ui:repeat

TagHandlers vs Components

The most important thing to understand about the JSTL tags in JSF 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

About Roger Keays

Roger is an active member of the JSF 2 Expert Group and is happy to be a contributor to the Java Community. He has been writing software since the age of 8 and his other interests include languages, science, travel and running.

Comment posted by: Mike Kienenberger, 7 years ago

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, 7 years ago
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: , 7 years ago

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, 7 years ago

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: , 7 years ago

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, 7 years ago

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, 7 years ago
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: , 7 years ago

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, 6 years ago

Thank you very much for this guide!!!

Comment posted by: hanafey, 6 years ago

<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, 6 years ago

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: , 6 years ago

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

Comment posted by: Rouche, 6 years ago

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: , 6 years ago

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, 6 years ago

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, 6 years ago

Another resource on the subject:

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

Comment posted by: Zel branco, 6 years ago

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, 6 years ago

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: Ivan, 5 years ago

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, 5 years ago

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

Comment posted by: Vlad, 5 years ago

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.

 

Comment posted by: David, 5 years ago

Hi,

I have created a list of files to download using ui:repeat.

I would like to know how can i know which element has been clicked from the list. This list can be different.

<ice:panelGroup>
<ui:repeat value="#{recursos.itemList}" var="item">
<h:panelGroup rendered="#{item.type== 'pdf'}">
<ice:outputText value="#{item.label}" />
<br />
<ice:outputResource id="pdfResource1"
label="#{msgs['download']}"
resource="#{resourceBean.pdfResourceDynFileName}"
mimeType="application/pdf" fileName="#{item.label}"
attachment="true" shared="false" style="width:150px" />
</h:panelGroup>
</ui:repeat>
</ice:panelGroup>

Any suggestions.

thanks

Comment posted by: Oliver, 5 years ago

Anyone tried to use really use <ui:include> ? How do you manage your id`s

Atm i have problems inside a loop and with using the templates at different locations (e.g. address template for customer main and secondary address) . For this i need to validate a little bigger context as only on field level scope.

Any examples out there how to solve such problems ? 

Comment posted by: Philip Murphy, 5 years ago

Hi,

I get most of what you are saying, but I can't for the life of me figure out why this works (i.e. creates a set of tabbed panels with one tab each):

<a4j:repeat value="#{myAction.events}" var="_event">
        <rich:tabPanel>
                <rich:tab label="#{_event.name}">
                </rich:tab>
        </rich:tabPanel>
</a4j:repeat>

and this doesn't (i.e. should create a set of tabs within a single tab panel)

<rich:tabPanel>
     <a4j:repeat value="#{myAction.events}" var="_event">
                <rich:tab label="#{_event.name}">
                </rich:tab>
    </a4j:repeat>
</rich:tabPanel>

My understanding is that the a4j:repeat is a component (similar to the ui:component), the rich:tabPanel is a component, and the rich:tab is a component.

Btw, the above code snippet is wraped in a repeating simpletogglepanel (created via a a4j:repeat) so I can't use c:forEach to create them.

Comment posted by: , 5 years ago

<rich:tabPanel> probably expects all its children to be <rich:tab>s and simply ignores the <a4j:repeat> component.

Comment posted by: Ronald van Kuijk, 5 years ago

No, rich:tabPanel with a c:forEach in it works. But if I add another tab, all are fully rerenderd. That is something I try to prevent now.

Comment posted by: Philip Murphy, 5 years ago

Hi,

Can someone explain this as I am a bit baffled?

If I use the old JSTL 1.0 tag library I can create a set of dynamic tabs using c:forEach, but if I use the newer JSTL 1.1 version it does not work.

For example:

`
<a4j:commandButton id="search" value="Search"
action="#{myBean.searchEvents}" reRender="myTabs" />

<rich:tabPanel id="myTabs" switchType="ajax">
  <c:forEach items="#{myBean.getEvents()}" var="_event">
    <rich:tab label="#{_event.name}" >
    </rich:tab>
  </c:forEach>
</rich:tabPanel

`

The above works fine if I include the following JSTL tag library (JSTL 1.0 - J2EE 1.3/JSP1.2):-

`
xmlns:c="http://java.sun.com/jstl/core"
`

However, if I include the following JSTL tag library it does not work (JSTL 1.1 - J2EE 1.4/JSP 2.0):-

`
xmlns:c="http://java.sun.com/jsp/jstl/core"
`

I am using the \#{} deferred EL syntax, however, it looks that when I am using the newer version that it is trying to evaluate the myBean.getEvents() before the events are actually populated by the submission of the Search button.

I am concerned that I am introducing a dependency on a old version of the JSTL library.

I am using JBoss 5.1.0 with Seam 2.2.

Comment posted by: spammer, 5 years ago

what a load of crap another java special; jstl/core does the trick !!! care to explain? consider ui:include where's the rendered there - an obvious lack of planning there

Comment posted by: Vincent, 5 years ago

 Thx for the blog, I was trying to build a sample application with a beta of jsf 2.0 and I ran into some this problems so quick.

It's really confusing for someone who is starting with jsf and you wont find this problems in all of those "quick cool ajax component in jsf 2.0" guides....

I just want a framework that has databinding, converters, validators and easy component creation, but I think all this is too much for me, I will never convince my colleagues if I have to explain all the problems you have to run into:

phase listeners, the whole encode/decode process, you have to know the component tree, bookmarking is not easy (there is no way to submit a form with nice get parameters ...)

I was really disappointed with jsf 1.2, and it seems that jsf 2.0 has more nice features, but you still have to run into many many WTF's.

Comment posted by: Sundaramurthi, 4 years ago

 Thanks. c:forEach inside dataTabe took long time to find issue..  going to drop considering iceface 

Comment posted by: Mike, 3 years ago

THANKS FOR THIS BLOG DUDE!!! It helped me ;)

Comment posted by: cliff, last year

 Just stumbled upon this as I was struggling with c:foreach, excellent write up.  Thank you!

Comment posted by: , last year

Glad you found it helpful Cliff. Don't forget to share to your favorite social network..

Comment posted by: Uwe Krull, last year

Great blog, dude, building a deeper understanding of important details. Thanks!

Best regards.

Comment posted by: zjtwtlycqc, last year
Comment posted by: jennahazel, last year
Comment posted by: ceciliaforeman, last year
Comment posted by: andreawilliamss, last year
Comment posted by: Carlos, last year

 hello I have a ,question it took days to estrus trabajndo with jfs and I have the following code inside a foreach q I list the questions and alternatives interrgante database is like saving my questions answered

  <h:form id="formAnswerReply">        
            <div align="left" style="background-color: #F3F3F3; border: 1px solid #E2E2E2; margin: 0 5px 5px; padding: 10px; margin-left: 40px; margin-right: 40px">
                <h:panelGrid columcolumns="1" cellspacing="5" style="padding-left: 30px">
                    <!--<p:tabView  backLabel="Anterior" nextLabel="Siguiente" id="wizarAnswer">-->
                    <c:forEach items="#{quizBean.quiz.quizChapterList}" var="quizChapter">
                        <strong> 
                            <h:outputText value="#{quizChapter.orderIn}-#{quizChapter.name}" style="font-size: 15px; font-style: italic"/>                            
                        </strong> 
                        <c:forEach items="#{quizChapter.chapterQuestionList}" var="chapterQuestion">
                            <h:outputText value="#{quizChapter.orderIn}.#{chapterQuestion.orderIn} - #{chapterQuestion.question}-#{chapterQuestion.choiceSetId.multipleSimple}" 
                                          style="padding-left: 15px; font-style: italic;"/>
                           <!-- <h:inputText value="#{chapterQuestion.id}"/>-->
                            <h:panelGrid columns="2" style="margin-bottom: 10px" cellpadding="5">
                                <c:set value="#{chapterQuestion.choiceSetId.multipleSimple}" var="value"/>
                                <c:if test="${value == true}">
                                    <h:selectManyCheckbox id="checkBoxAternative" value="#{quizBean.choice}" required="true" style="margin-left: 35px; margin-right: 6px">
                                        <f:selectItems value="#{chapterQuestion.choiceSetId.choiceList}"
                                                       var="choiceID"                                                      
                                                       itemLabel="#{choiceID.name}" 
                                                       itemValue="#{choiceID.id}"/>
                                    </h:selectManyCheckbox>
                                </c:if>
                                <c:if test="${value == false}">
                                    <p:selectOneRadio id="radioButtonAlternative" value="#{quizBean.choice}" required="true" style="margin-left: 35px; margin-right: 6px">
                                        <f:selectItems value="#{chapterQuestion.choiceSetId.choiceList}" 
                                                       var="choiceID"
                                                       itemLabel="#{choiceID.name}" itemValue="#{choiceID.id}"/>
                                    </p:selectOneRadio>
                                </c:if>                               
                            </h:panelGrid>                       
                        </c:forEach>
                    </c:forEach>                       
                </h:panelGrid><br/><br/>   
            </div>
            <div align="right" style="margin-right: 40px">
                <p:commandButton value="Enviar Encuesta" icon="ui-icon-disk"/>
                <p:commandButton id="idSaveQuestions" value="Responder" icon="ui-icon-check" action="#{quizBean.mostrar}">                  
                </p:commandButton>
            </div>
        </h:form>
Comment posted by: Carlos, last year

 hello I have a ,question it took days to estrus trabajndo with jfs and I have the following code inside a foreach q I list the questions and alternatives interrgante database is like saving my questions answered

  <h:form id="formAnswerReply">        
            <div align="left" style="background-color: #F3F3F3; border: 1px solid #E2E2E2; margin: 0 5px 5px; padding: 10px; margin-left: 40px; margin-right: 40px">
                <h:panelGrid columcolumns="1" cellspacing="5" style="padding-left: 30px">
                    <!--<p:tabView  backLabel="Anterior" nextLabel="Siguiente" id="wizarAnswer">-->
                    <c:forEach items="#{quizBean.quiz.quizChapterList}" var="quizChapter">
                        <strong> 
                            <h:outputText value="#{quizChapter.orderIn}-#{quizChapter.name}" style="font-size: 15px; font-style: italic"/>                            
                        </strong> 
                        <c:forEach items="#{quizChapter.chapterQuestionList}" var="chapterQuestion">
                            <h:outputText value="#{quizChapter.orderIn}.#{chapterQuestion.orderIn} - #{chapterQuestion.question}-#{chapterQuestion.choiceSetId.multipleSimple}" 
                                          style="padding-left: 15px; font-style: italic;"/>
                           <!-- <h:inputText value="#{chapterQuestion.id}"/>-->
                            <h:panelGrid columns="2" style="margin-bottom: 10px" cellpadding="5">
                                <c:set value="#{chapterQuestion.choiceSetId.multipleSimple}" var="value"/>
                                <c:if test="${value == true}">
                                    <h:selectManyCheckbox id="checkBoxAternative" value="#{quizBean.choice}" required="true" style="margin-left: 35px; margin-right: 6px">
                                        <f:selectItems value="#{chapterQuestion.choiceSetId.choiceList}"
                                                       var="choiceID"                                                      
                                                       itemLabel="#{choiceID.name}" 
                                                       itemValue="#{choiceID.id}"/>
                                    </h:selectManyCheckbox>
                                </c:if>
                                <c:if test="${value == false}">
                                    <p:selectOneRadio id="radioButtonAlternative" value="#{quizBean.choice}" required="true" style="margin-left: 35px; margin-right: 6px">
                                        <f:selectItems value="#{chapterQuestion.choiceSetId.choiceList}" 
                                                       var="choiceID"
                                                       itemLabel="#{choiceID.name}" itemValue="#{choiceID.id}"/>
                                    </p:selectOneRadio>
                                </c:if>                               
                            </h:panelGrid>                       
                        </c:forEach>
                    </c:forEach>                       
                </h:panelGrid><br/><br/>   
            </div>
            <div align="right" style="margin-right: 40px">
                <p:commandButton value="Enviar Encuesta" icon="ui-icon-disk"/>
                <p:commandButton id="idSaveQuestions" value="Responder" icon="ui-icon-check" action="#{quizBean.mostrar}">                  
                </p:commandButton>
            </div>
        </h:form>

Add a comment

Please visit http://www.NinthAvenue.com.au/jsf-c-foreach-vs-ui-repeat to add your comments.

Join The Mailing List

Subscribe to our mailing list for the latest news and announcements.

Follow Ninth Avenue

Website Updates