In this tutorial, I will show you how to bind and validate a multi row form, as figure bellow.
Option.java
User.java
This bean store the information of an User
And a form bean UserForm.java
There is only one user list in this form
We need these tag lib
The form attribute is users
To loop through a list, we use the core tag lib
As the figure above, I will show you 4 types of component
That is enough for binding a mutil row form, next we discuss about validation
Here I just show you how to create a error message for an attribute in list.
The difference with the validation of a bean is the error field name is under list format errors.rejectValue("lstUser[" + i + "].name.
To display an error message on form, we use status.errorMessage in <spring:bind>
Related:
References:
- For binding Multi Row, I use the <spring:bind> tag lib
- For validation, I use the manual validation (by inheriting the spring validator interface)
To start, let create these beans:
Option.java
public class Option { private String value; private String label; ... }This bean used in creating the list of option in select tag, the list of checkboxs....
User.java
public class User { // a text box private String name; // check boxs private String[] hobbies; // a radio private String sex; // options private String[] countries; ... }
This bean store the information of an User
And a form bean UserForm.java
public class UserForm { private List<User> lstUser; ... }
There is only one user list in this form
Modify User Form
We need these tag lib
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
The form attribute is users
<form:form action="/multirow/modifyUser" method="POST" modelAttribute="users">
To loop through a list, we use the core tag lib
<c:forEach items="${users.lstUser}" var="user" varStatus="loopStatus">
As the figure above, I will show you 4 types of component
1. Text Box
<spring:bind path="users.lstUser[${loopStatus.index}].name"> <input type="text" name="<%=status.getExpression() %>" value="<%=status.getValue() %>" /> </spring:bind>
- Make attention at the path of spring:bind tag lib, here we are defining a list of name attribute
- status.getExpression() returns the html name
- status.getValue() returns the value of name attribute
2. Multi Check box
<spring:bind path="users.lstUser[${loopStatus.index}].hobbies"> <c:forEach items="${lstHobby}" var="hobby"> <c:set var="checkMe" value="" /> <c:forEach items="${status.actualValue}" var="curValue"> <c:if test="${curValue == hobby.value}"> <c:set var="checkMe" value="checked" /> </c:if> </c:forEach> <input type="checkbox" name="<%=status.getExpression() %>" value="${hobby.value}" <c:out value="${checkMe }"/> />${hobby.label } </c:forEach> </spring:bind>
3. Radio Button
<c:set var="male" value="M"/> <c:set var="female" value="F"/> <spring:bind path="users.lstUser[${loopStatus.index}].sex"> <input type="radio" name="<%=status.getExpression()%>" value="${male }" <c:if test="${male == status.value }">checked</c:if> />Male <input type="radio" name="<%=status.getExpression()%>" value="${female }" <c:if test="${female == status.value }">checked</c:if> />Female <div><c:out value="${status.errorMessage }" /></div> </spring:bind>
4. Select
<spring:bind path="users.lstUser[${loopStatus.index}].countries"> <select name="<%=status.getExpression() %>"> <option value="NONE">---SELECT---</option> <c:forEach items="${lstCountry }" var="country"> <c:set var="selectMe" value="" /> <c:forEach items="${status.actualValue}" var="curValue"> <c:if test="${curValue == country.value}"> <c:set var="selectMe" value="selected" /> </c:if> </c:forEach> <option value="${country.value }" ${selectMe } > ${country.label } </option> </c:forEach> </select> </spring:bind>
Tip
When we compare 2 variables of type String, the <c:if test> uses the equals function to compare them
When we compare 2 variables of type String, the <c:if test> uses the equals function to compare them
That is enough for binding a mutil row form, next we discuss about validation
Here I just show you how to create a error message for an attribute in list.
public void validate(Object obj, Errors errors) { UserForm form = (UserForm) obj; List<User> lstUser = form.getLstUser(); if (lstUser == null) { return; } for (int i = 0; i < lstUser.size(); i++) { User user = lstUser.get(i); if (user.getName() == null || "".equals(user.getName().trim())) { errors.rejectValue("lstUser[" + i + "].name", "user.name.required"); } } }
The difference with the validation of a bean is the error field name is under list format errors.rejectValue("lstUser[" + i + "].name.
To display an error message on form, we use status.errorMessage in <spring:bind>
<spring:bind path="users.lstUser[${loopStatus.index}].name"> ... <span class="errors"><c:out value="${status.errorMessage }" /></span> </spring:bind>
Related:
References:
- https://jira.springsource.org/browse/SPR-52
- http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/support/BindStatus.html
- http://stackoverflow.com/questions/12680730/validate-a-list-of-nested-objects-with-spring-validator
Source code:
- For the demonstration, please download source code from HERE
- My repository on Github, download ALL SOURCE code in this blog