The ForEach Tag

The "forEach" tag is a looping tag that allows looping over bean values that are Collections. This tag must contain a body. The tag's block of cells is copied and processed once for each collection element found.

Attributes

  • The "forEach" tag supports all base tag attributes.
  • The "forEach" tag supports all looping tag attributes.
  • items: Collection Required. This specifies the Collection over which to iterate.
  • var: String Required. This specifies the name of the variable to be exposed in the beans map for the collection item, i.e. the looping variable.
  • where: Boolean Optional. This specifies a condition under which a collection item will be displayed. Items for which this condition is false will not be displayed.
  • limit: int Optional. This specifies a limit to the number of Collection items displayed. If the collection size is less than the limit, then the block of cells is copied for the extra non-existent items, but the cells are left blank. For example, if the Collection has 7 items, and the limit is 10, then 10 rows are produced, one for each of the 7 items, and 3 additional blank rows.
  • indexVar: String Optional. This specifies an integer "counter" variable name to be exposed in the beans map. This variable starts at index zero.
  • groupBy: List<String> Optional. Specify a list of properties to partition the collection into sublists, where each member of a sublist has properties that compare equal. Specify an actual List or a semicolon-separated string of property names. If this is specified, then the variable specified by the var attribute will be a Group, which has the following properties available:
    • obj This property contains the representative object, which holds one item from the collection to represent all items with the same group-by properties.
    • items This property contains a List of all items whose group-by properties are the same. The representative object is present in this list. This can be used as the items attribute in a nested "forEach" tag.
  • orderBy: List<String> Optional. Specify a list of properties by which to order the collection before display. This option works whether the groupBy attribute is specified or not. Specify an actual List or a semicolon-separated string of property names. Ascending or descending can be specified for each property, as well as whether to place null values first or last. The default ordering for each property is ascending, nulls last. If descending, then nulls default to first. Here is the format for each order-by property:
    • propertyName [asc|desc] [nulls [first|last]]

Examples

There are 4 Employees, 2 of which have a manager. Notice the use of the nested if tag to conditionally display the manager name and avoid a NullPointerException.

Employee Salary Manager
<jt:forEach items="${employees}" var="employee">${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach>

...gets transformed into...

Employee Salary Manager
Stack, Robert $1000.00  
Queue, Suzie $900.00 Stack, Robert
Fudd, Elmer $800.00 Stack, Robert
Bunny, Bugs $1500.00  

Copy Right Example

Here's an example that uses the "copyRight" attribute.

<jt:forEach items="${numberList}" var="number" copyRight="true">${number}</jt:forEach> Shift me right!      

...gets transformed into...

3 23 100 -10 Shift me right!

Where Example

Here's an example that uses the "where" attribute, limiting those records displayed to those with a salary greater than or equal to 900.

Employee Salary Manager
<jt:forEach items="${employees}" var="employee" where="${employee.salary >= 900}">${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach>

...gets transformed into...

Employee Salary Manager
Stack, Robert $1000.00  
Queue, Suzie $900.00 Stack, Robert
Bunny, Bugs $1500.00  

Limit Example

Here's an example that uses the "limit" attribute, once with a limit less than the collection size, and once with a limit more than the collection size.

Employee Salary Manager
<jt:forEach items="${employees}" var="employee" limit="${limit}">${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach>
Content Below the Block

...if "limit" is only 2, then it gets transformed into...

Employee Salary Manager
Stack, Robert $1000.00  
Queue, Suzie $900.00 Stack, Robert
Content Below the Block

...but if "limit" is 6, then it gets transformed into...

Employee Salary Manager
Stack, Robert $1000.00  
Queue, Suzie $900.00 Stack, Robert
Fudd, Elmer $800.00 Stack, Robert
Bunny, Bugs $1500.00  
     
     
Content Below the Block

Fixed Example

Here's an example that uses the "fixed" attribute. Notice how there is already room for the collection content, and that any content below the block does not get shifted.

Employee Salary Manager
<jt:forEach items="${employees}" var="employee" fixed="true">${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach>
     
     
     
I am not getting moved!

...gets transformed into...

Employee Salary Manager
Stack, Robert $1000.00  
Queue, Suzie $900.00 Stack, Robert
Fudd, Elmer $800.00 Stack, Robert
Bunny, Bugs $1500.00  
I am not getting moved!

IndexVar Example

Here's an example that uses the "indexVar" attribute. Notice that the variable is zero-based, and one is added so it can start with "1.".

Employee Salary Manager
<jt:forEach items="${employees}" var="employee" indexVar="index">${index + 1}. ${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach>

...gets transformed into...

Employee Salary Manager
1. Stack, Robert $1000.00  
2. Queue, Suzie $900.00 Stack, Robert
3. Fudd, Elmer $800.00 Stack, Robert
4. Bunny, Bugs $1500.00  

GroupBy Example

Here's an example that uses the "groupBy" attribute. Notice that there are two employees in each of two departments.

<jt:forEach items="${employees}" var="dept" groupBy="deptName">Department Name: ${dept.obj.deptName}
<jt:forEach items="${dept.items}" var="employee">Employee Salary Manager
${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach></jt:forEach>

...gets transformed into...

Department Name: Cartoon Characters
Employee Salary Manager
Fudd, Elmer $800.00 Stack, Robert
Bunny, Bugs $1500.00  
Department Name: Data Structures Programmers
Employee Salary Manager
Stack, Robert $1000.00  
Queue, Suzie $900.00 Stack, Robert

OrderBy Example

Building on the "groupBy" example, this example adds an "orderBy" attribute. The "orderBy" attribute works well with or without a "groupBy" attribute. But if both are present, then any "orderBy" properties that are present in the "groupBy" attribute must be specified BEFORE any "orderBy" properties that are not present in the "groupBy" attribute.

<jt:forEach items="${employees}" var="dept" groupBy="deptName" orderBy="deptName desc;lastName">Department Name: ${dept.obj.deptName}
<jt:forEach items="${dept.items}" var="employee">Employee Salary Manager
${employee.lastName}, ${employee.firstName} ${employee.salary} <jt:if test="${employee.getManager() != null}" then="${employee.manager.lastName}, ${employee.manager.firstName}"/></jt:forEach></jt:forEach>

...gets transformed into...

Department Name: Data Structures Programmers
Employee Salary Manager
Queue, Suzie $900.00 Stack, Robert
Stack, Robert $1000.00  
Department Name: Cartoon Characters
Employee Salary Manager
Bunny, Bugs $1500.00  
Fudd, Elmer $800.00 Stack, Robert