Basic
Selecting lines
Style and colors
Links
Sort
Editing data in a list
Data swap
Nested collection
Parallel iteration
Block iteration
Master/detail
Statistics
Scrolling
Very simple example. Let's suppose there is a collection under the name "users" in the request scope which contains object having the properties login, firstname, lastname, and society
... <layout:collection name="users" styleClass="ARRAY"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionItem title="users.firstname" property="firstname"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society" property="society"/> </layout:collection> ...
Now, we want to display something very specific for the society column (for example, the society logo). We suppose the getSociety() method of the bean returns a society object which has a getLogo() method.
... <layout:collection name="users" styleClass="ARRAY" id="user"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionItem title="users.firstname" property="firstname"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society"> <img src="/myApplication/pathToSocietyLogo/<bean:write name="user" property="society.logo"/>" border="0"> </layout:collectionItem> </layout:collection> ...
Click here to see the running examples
The struts-layout collectionItem tag can be used with different parameters specified, and with or without a body content.
<%@page import="fr.improve.struts.webapp.layout.example.User,java.util.Vector" %>
<%@taglib uri="/WEB-INF/struts-layout.tld" prefix="layout" %>
<% Vector v = new Vector();
User user = new User();
user.setFullName("John Smith");
user.setUsername("jsmith");
User user2 = new User();
user2.setFullName("Jean Durand");
user2.setUsername("jdurand");
v.add(user); v.add(user2); pageContext.setAttribute("users", v);
%>
<html>
<head>
<link rel="stylesheet" href='../config/skin2.css' type="text/css">
</head>
<body>
<layout:collection name="users" title="Users" styleClass="FORM">
<layout:collectionItem title="Login" property="username"/>
<layout:collectionItem title="Name" property="fullName"/>
<layout:collectionItem title="Edit" url="collectionItem2.jsp?user=" param="username" property="fullName"/>
<layout:collectionItem title="Delete" url="collectionItem3.jsp?user=" param="username" property="fullName" onclick="return confirm('Really delete the user ?');">
<layout:collectionItem title="DoSomething" url="collectionItem4.jsp" paramId="fuLlNaMe,uSeRnAmE" paramProperty="fullName,username" property="fullName"/>
Delete
</layout:collectionItem>
</layout:collection>
</body>
</html>
Nesting logic tags inside a collection tag is difficult, because the current implementation does an initial iteration to display the headers. In this iteration, no iteration bean is defined, so <logic:present> tags must be used before testing the bean value.
If the collection tag is nested in a form tag, it is possible to display radio buttons to select a bean in a collection.
The selectProperty attribute specifies which property of the beans should be use to set the value of the input fields generated.
The name of the input fields is the one of the selectProperty specified. It can be changed by setting the selectName attribute. In this case, the radio buttons / checkbox are checked in function of the correspondig form bean property value.
The selectType attribute can take the values "radio" or "checkbox" to allow to select one or many values.
In the following example, we want to be able to select one user. When we submit the form, the id parameter contains the login of the selected user.
... <layout:collection name="users" styleClass="ARRAY" selectName="id" selectProperty="login" selectType="radio"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionItem title="users.firstname" property="firstname"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society" property="society"/> </layout:collection> ...
Now, we want to be able to select multiple users. When we submit the form, the ids parameter contains the logins of the selected user. The ids property should be an indexed property in the struts bean form.
... <layout:collection name="users" styleClass="ARRAY" selectName="ids" selectProperty="login" selectType="checkbox"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionItem title="users.firstname" property="firstname"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society" property="society"/> </layout:collection> ...
The collection tag allows to easily alternates the row colors by using the styleClass and styleClass2 attributes.
Example:
<%@page import="fr.improve.struts.webapp.layout.example.User,java.util.Vector" %>
<%@taglib uri="/WEB-INF/struts-layout.tld" prefix="layout" %>
Vector v = new Vector();
User user = new User();
user.setFullName("John Smith");
user.setUsername("jsmith");
User user2 = new User();
user2.setFullName("Jean Durand");
user2.setUsername("jdurand");
User user3 = new User();
user3.setFullName("Jacques Dupond");
user3.setUsername("jdupond");
v.add(user); v.add(user2); v.add(user3); v.add(user); v.add(user2); v.add(user3); pageContext.setAttribute("users", v);
%>
<html>
<head>
<link rel="stylesheet" href='../config/skin2.css' type="text/css">
</head>
<body>
<layout:collection name="users" title="Users" styleClass="FORM" styleClass2="FORM2" width="400">
<layout:collectionItem title="Login" property="username"/>
<layout:collectionItem title="Name" property="fullName"/>
<layout:collectionItem title="Edit" url="collectionItem2.jsp?user=" param="username" property="fullName"/>
<layout:collectionItem title="Delete" url="collectionItem3.jsp?user=" param="username" onclick="return confirm('Really delete the user ?');">Delete</layout:collectionItem>
</layout:collection>
</body>
</html>
Now we want to highlight users whose firstname is Pierre. This can be done with the collectionStyle tag.
... <layout:collection name="users" styleClass="ARRAY" id="user"> <layout:collectionStyle name="user" property="firstname" value="Pierre" matchStyleClass="ARRAY2"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionItem title="users.firstname" property="firstname"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society" property="society"/> </layout:collectionStyle> </layout:collection> ...
Now, we want to display a link to the user information action. The action needs the login of the user to be in the parameter uid
... <layout:collection name="users" styleClass="ARRAY"> <layout:collectionItem title="users.login" property="login" href="user.do" paramId="uid" paramProperty="login"/> <layout:collectionItem title="users.firstname" property="firstname"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society" property="society"/> </layout:collection> ...
Is is possible to automatically sort a collection, on the server or on the client.
The properties of the beans that are sortable must be indicated by setting the attribute "sortable" of the collectionItem tag to true.
The sort can be done:
There is an example of the default sort action in the demonstration, on the registration page. Here is an exemple of the javascript sort action.
By default, the sort action won't work if the back button is hit. In this case, struts-layout will detect an error and forward to an action forward named "sortError". This can be configured in the struts-layout properties file.
In the following example, we want to be able to sort the collection by users login and firstname
... <layout:collection name="users" styleClass="ARRAY" sortAction="client"> <layout:collectionItem title="users.login" property="login" sortable="true"/> <layout:collectionItem title="users.firstname" property="firstname" sortable="true"/> <layout:collectionItem title="users.lastname" property="lastname"/> <layout:collectionItem title="users.society" property="society"/> </layout:collection> ...
If the collection tag is nested in a form tag, it is possible to put input field in the cells by using the collectionInput tag.
In the following example, we want to edit the user firstname and lastname. We can do this with the collectionInput tag. This example suppose there are two indexed properties called firstname and lastname in the form bean associated to the updateUsernames action.
... <layout:form action="/updateUsernames"> ... <layout:collection name="users" styleClass="ARRAY"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionInput title="users.firstname" property="firstname" formProperty="firstname"/> <layout:collectionInput title="users.firstname" property="lastname" formProperty="lastname"/> </layout:collection> ... </layout:form> ...
Now, we want to use mapped properties in the form instead of indexed properties. This way we don't have to worry about the order and numbers of the elements. This example suppose the firstname and lastname properties of the form bean are mapped properties. When processing the action, we will be able to get the new names of a user by specifying its login
... <layout:form action="/updateUsernames"> ... <layout:collection name="users" styleClass="ARRAY"> <layout:collectionItem title="users.login" property="login"/> <layout:collectionInput title="users.firstname" property="firstname" formProperty="firstname" keyProperty="login"/> <layout:collectionInput title="users.firstname" property="lastname" formProperty="lastname" keyProperty="login"/> </layout:collection> ... </layout:form> ...
The collectionInput tag allows to build only text input field, and is rather complicated to use. It's usually easier to use the usual <layout:text>, <layout:textarea>, <layout:select>, <layout:checkbox>, <layout:radio> tags. This requires to set the property of the tag with an EL :
<layout:form action="/someAction">
<layout:collection property="aCollectionInFheForm" indexId="index">
<layout:collectionItem title="some.title">
<layout:checkbox property="aCollectionIntheForm[${index}].aBooleanProperty" layout="false"/>
</layout:collectionItem>
</layout:collection>
</layout:form>
In this example, the Struts form bean as a java.util.Collection property named "aCollectionInTheForm". This collection contains object which have a boolean property named "aBooleanProperty". The layout="false" attribute tells the checkox tag to not render title and HTML positionning code.
Now we want to move users between two lists. We can do this with the swap tag
This example suppose:
... <layout:form action="/swap.do" reqCode="displayResult"> <layout:line> <layout:swap property="username,username" formProperty="users1,users2" selectedStyleClass="FORMSWAP"> <layout:collection name="list1" styleClass="FORM" height="150" > <layout:collectionItem title="Login" property="username"/> <layout:collectionItem title="Name" property="fullName"/> </layout:collection> <layout:collection name="list2" styleClass="FORM" height="150"> <layout:collectionItem title="Login" property="username"/> <layout:collectionItem title="Name" property="fullName"/> </layout:collection> </layout:swap> <layout:submit valign="top">Submit</layout:submit> </layout:line> ...
Here is a running example
The following code displays the list of mail account of a list of user
This example suppose:
... <layout:collection name="v" id="bean1" title="User" styleClass="FORM"> <layout:collectionItem title="Name" name="bean1" property="lastname"/> <layout:collectionItem title="Firstname" name="bean1" property="firstname"/> <layout:nestedCollection property="subscriptions" id="bean2"> <layout:collectionItem title="Subscriptions" name="bean2" property="host"/> </layout:nestedCollection> </layout:collection> ...
The result is viewable here.
The struts-layout collection and news tag allow to iterate two collections at the same time. The following example shows how to do this.
<%@page import="java.util.Vector" %>
<%@taglib uri="/WEB-INF/struts-layout.tld" prefix="layout" %>
<% Vector v1 = new Vector();
v1.add("item1");
v1.add("item2");
v1.add("item3");
Vector v2 = new Vector();
v2.add("5$");
v2.add("3$");
v2.add("9$");
pageContext.setAttribute("v1", v1); pageContext.setAttribute("v2", v2);
%>
<html>
<head>
<link rel="stylesheet" href='../config/skin2.css' type="text/css">
</head>
<body>
<layout:collection name="v1" id="bean1" name2="v2" id2="bean2" title="Item price" styleClass="FORM">
<layout:collectionItem title="Item" name="bean1"/>
<layout:collectionItem title="Price" name="bean2"/>
</layout:collection>
</body>
</html>
The <layout:table> tag makes it possible to iterate over a collection and to present the result in a table of a given number of columns. Here is an exemple:
<@page import="java.util.Vector"%>
<%@taglib uri="/WEB-INF/struts-layout.tld" prefix="layout" %>
<%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<% Vector v = new Vector();
v.add("This");
v.add(" ");
v.add("is");
v.add(" ");
v.add("a");
v.add(" ");
v.add("very");
v.add(" ");
v.add("simple");
v.add(" ");
v.add("example.");
pageContext.setAttribute("v", v);
%>
<html>
<body>
<layout:table name="v" id="mot" col="3">
<bean:write name="mot"/>
</layout:table>
</body>
</html>
<layout:column> <layout:collection name="billets" model="green" id="billet" indexId="index"> <layout:collectionItem title="liste.titre" property="titre" sortable="true"/> <layout:collectionItem title="liste.dossier" property="dossier" sortable="true"/> <layout:collectionItem title="liste.montant" property="montant" sortable="true" width="75"/> <layout:collectionDetail property="fournisseur"/> <layout:collectionDetail property="voyageur"/> <layout:collectionDetail property="factureClient"/> </layout:collection> <layout:grid cols="3" styleClass="DETAILGRID"> <layout:detail key="detail.fournisseur" property="fournisseur" styleClass="DETAIL"/> <layout:detail key="detail.voyageur" property="voyageur" styleClass="DETAIL"/> <layout:detail key="detail.facture" property="factureClient" styleClass="DETAIL"/> </layout:grid> </layout:column>
The titre, dossier and montant properties are displayed as columns, the fournisseur, voyageur and facture properties are displayed as details.
First, you need to put commons-math.jar from the Jakarta Commons project in your classpath. Second, and only if you have change the default collection renderer, you need to have your collection renderer implements the interface fr.improve.struts.taglib.layout.util.IMathCollectionRenderer.
The following operations are supported : geometricMean, max, mean, min, product, sum, sumLog, sumSq, variance
Simply set the width or height attribute to set the collection size onscreen. Scrollbars will appear automatically. Example :
... <layout:collection name="users" title="Users" styleClass="SCROLL" height="200"> ... </layout:collection> ...
Struts-Layout provides two specific renderers that can fix collection headers :
To use the renderers, you need to declare them in the Struts-Layout configuration file. Have a look at how to do this here You can seew the renderers in action here :
To get the examples source code, download the MailReader example application and check the examples/collectionScrollable.jsp and example/collectionScrollable2.jsp.