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