c:forEach and HTML tables

Using script to create a table from a collection of data leads to a mix of Java and HTLM code that is messy, to say the least.

The JSTL core forEach tag helps us to get rid of scripting and writing HTLM code that is easy to read and to maintain.

As an example, think of a list of films, created in servlet in this way:
String[] movies = {"Amelie", "El laberinto del fauno", "The Godfather"};
request.setAttribute("movieList", movies);

To generate a table in a JSP page having access to the movieList attribute we would normally write something like that, using some scripting:
<table>
<%
    String[] items = (String[]) request.getAttribute("movieList");
    String var=null;
    for (int i = 0; i < items.length; i++) {
    var = items[i];
%>
    <tr>
        <td><%= var %></td>
    </tr>
<% } %>
</table>
Not exactely what someone would call a beautiful piece of code. Compare it with the same code written using the forEach tag:
<table>
    <c:forEach var="movie" items="${movieList}">
        <tr>
            <td>${movie}</td>
        </tr>
    </c:forEach>
</table>
Remember that, before using the standard tags, your code should have access to the JSTL core library.

We loop on forEach for each element in the list passed in the items attribute. The loop variable is specified in the var attribute, and it has scope limited to the loop itself.

Another attribute in forEach is varStatus, that we could use for keeping track of the current count of the item we are working with. Notice that the count is a "natural" one, and not a C-style. That means, first item has count 1 (and not 0).

With this excerpt we print a table where in the first column we put the current index, and in the second one the value:
<table>
    <c:forEach var="movie" items="${movieList}" varStatus="status">
        <tr>
            <td>${status.count}</td>
            <td>${movie}</td>
        </tr>
    </c:forEach>
</table>
Let's now change the data created in the servlet. We create a list of String arrays, and we put it in a request attribute:
String[] movies2 = {"Play Time", "Up", "Infamous"};
java.util.List<String[]> movieList2 = new java.util.ArrayList<String[]>();
movieList2.add(movies);
movieList2.add(movies2);
request.setAttribute("movies", movieList2);
To put all the data in a table we have to do two nested forEach, the first looping on the list elements, the second on the array ones. This is not a problem at all, as we can see here:
<table>
    <c:forEach var="list" items="${movies}" varStatus="movieLoopCount">
        <tr>
            <td>${movieLoopCount.count}</td>
        </tr>
        <c:forEach var="movie" items="${list}">
            <tr>
                <td>${movie}</td>
            </tr>
        </c:forEach>
    </c:forEach>
</table>
For more stuff on custom tag, I'd suggest you to have a look at Head First Servlet and JSP, chapter nine. I was actually reading it when I wrote the first version of this post.

No comments:

Post a Comment