Summary

Tag name: <af:forEach>

The forEach tag is a replacement for the JSTL <c:forEach> tag. Though as of JSF 1.2/JSP 2.1/JSTL 1.2, <c:forEach> can be used with any JSF components or tags, it does not support "varStatus" when used with deferred evaluation. This tag adds support for varStatus (other than "current" which is not supported). (Note: this tag is not supported in Facelets, because c:forEach is fully functional in Facelets.) Unlike the old ADF af:forEach built with JSF 1.1, however, this tag can be used with any JSP 2.1-based tag, JSF or non-JSF. This tag also has a limitation not found in <c:forEach>: <af:forEach> does not currently support arbitrary java.util.Collections; it can only iterate over java.util.Lists or arrays.

Caution

The forEach tag should be used with intent and knowledge. The forEach tag is not used in JSF for iteration, but instead for generating multiple components. If your goal is to iterate over a collection of objects and render HTML for each item, <af:iterator> should be using instead.

Instances when <af:forEach> would be needed instead of <af:iterator>:

  • Components should be created conditionally based on the item in the loop. This may be in conjuction with <c:if>, <c:choose>, <c:when> and <c:otherwise> tags.
  • Different JSP includes, page templates, and dynamic declarative components should be included per loop iteration. For example:
    <af:forEach var="item" items="#{bean.views}">
      <af:declarativeComponent viewId="#{item.viewId} />
    </af:ForEach>
          
  • When <af:iterator/> is not supported as a child. This usually occurs in Trinidad, but the RichClient components are written to support iterator
<af:forEach> may cause issues with component IDs

There may only be one component in a naming container with an ID. Therefore, if a component that is created as a child of a for each loop has an explicit ID set, JSF will alter the IDs of components beyond the first one. This can break partial triggers, behaviors and other components that refer to a component.

Objects in the items of an <af:forEach> tag should not be added, removed or re-ordered once the component tree has been created

For each loops are made to work in JSP, and have been altered to support JSF at a basic level only. The components that are created while looping over the for each loop store their indexes of when the component was first created. This means that if, say for example, the first item is removed from the items collection, the component at index 1, which now is index 0 still retains index 1. As a result, the EL expressions of the component will return the incorrect item when the var is resolved. Problems may also occur if explicit IDs are not given with component state. The component state is tied to the index of the component, not to the item in the items collection.

Children of <af:forEach> cannot share a binding EL value

A component instance may only exist once in a component tree. Therefore, if it is desired to have the component bound to a managed bean, the binding must evaluate to a different bean property for every iteration of the loop. For example:

<af:forEach var="item" items="#{bean.items}">
  <!-- Note that the output text component is bound to the item, not the bean -->
  <af:outputText binding="#{item.outputText}" />
</af:ForEach>
    

Code Example(s)

  <af:selectOneListbox value="#{someValue}">
    <af:forEach var="item" items="#{model.listOfItems}">
      <af:selectItem value="#{item.value}" label="#{item.text}"/>
    </af:forEach>
  </af:selectOneListbox>

Managed Bean code snippet for the above jspx snippet

import javax.faces.model.SelectItem;

public class TestBean
{
  public TestBean()
  {
    listOfItems = new ArrayList();
    listOfItems.add(new SelectItem("value1", "label1"));//value and label
    listOfItems.add(new SelectItem("value2", "label2"));
    listOfItems.add(new SelectItem("value3", "label3"));
    listOfItems.add(new SelectItem("value4", "label4"));
  }
  
  private List listOfItems;

  public void setListOfItems(List listOfItems)
  {
    this.listOfItems = listOfItems;
  }

  public List getListOfItems()
  {
    return listOfItems;
  }
}
  <af:forEach varStatus="vs" begin="1" end="5">
    <af:outputText id="ot2" value="#{vs.index} #{vs.count} #{vs.begin}"/>
  </af:forEach>

Attributes

Name Type Supports EL? Description
begin int No index at which iteration begins
end int No index at which iteration ends
items Object Only EL the collection to iterate over
step int No number to increment on each iteration
var String No name of the variable exposed when iterating
varStatus String No name of the loop status exposed when iterating. The properties 'index','count','begin','end','step','first','last' are available through this