Why are these Seam field values not binding? - xhtml

I am building a a simple research routine whith 2 date fields a selectOneMenu and a button:
<h:form id="pesquisaAbastecimentoForm">
<table>
<tr>
<td>
<s:decorate id="dataInicialField" template="../layout/edit.xhtml">
<ui:define name="label" id="labelDataInicial">Data Inicial</ui:define>
<rich:calendar id="dataInicial" value="#{abastecimentoAction.dataInicialPesquisa}"
datePattern="dd/MM/yyyy HH:mm" />
</s:decorate>
<s:decorate id="dataFinalField" template="../layout/edit.xhtml">
<ui:define name="label" id="labalDataFinal">Data Final</ui:define>
<rich:calendar id="dataFinal" value="#{abastecimentoAction.dataFinalPesquisa}"
datePattern="dd/MM/yyyy HH:mm" />
</s:decorate>
</td>
<td>
<s:decorate id="carroField" template="../layout/edit.xhtml">
<ui:define name="label">Carro</ui:define>
<h:selectOneMenu value="#{abastecimentoAction.idCarroPesquisa}" required="false">
<s:selectItems var="carro" value="#{carroList.resultList}" label="#{carro.nome}" itemValue="#{carro.id}" />
</h:selectOneMenu>
</s:decorate>
<s:div styleClass="actionButtons">
<s:button action="#{abastecimentoAction.pesquisaAbasatecimentos}" id="pesquisaAbastecimentos" value="Pesquisar Abastecimento">
</s:button>
</s:div>
</td>
</tr>
</table>
</h:form>
And I have a seam component which should get the values and get the method pesquisaAbastecimentos executed.
#Name("abastecimentoAction")
#Scope(ScopeType.CONVERSATION)
public class AbastecimentoAction implements Serializable {
private static final long serialVersionUID = -2008939547568730028L;
#Logger
Log log;
#In
EntityManager entityManager;
#In
User user;
//variáveis para pesquisa do abastecimento
private Date dataInicialPesquisa;
private Date dataFinalPesquisa;
private int idCarroPesquisa;
#DataModel
List<AbastecimentoMensal> listaAbastecimentoMensal;
#SuppressWarnings("unchecked")
#Create
public void pesquisaAbasatecimentos() { ... }
public Date getDataInicialPesquisa() {
return dataInicialPesquisa;
}
public void setDataInicialPesquisa(Date dataInicialPesquisa) {
this.dataInicialPesquisa = dataInicialPesquisa;
}
public Date getDataFinalPesquisa() {
return dataFinalPesquisa;
}
public void setDataFinalPesquisa(Date dataFinalPesquisa) {
this.dataFinalPesquisa = dataFinalPesquisa;
}
public int getIdCarroPesquisa() {
return idCarroPesquisa;
}
public void setIdCarroPesquisa(int idCarroPesquisa) {
this.idCarroPesquisa = idCarroPesquisa;
}
The method is correctly executed but the values for the fields are never populated. As I am relatively new to seam I could not find out why these fields are not being correctly filled by seam framework. The values are actually null and 0 when the button is pressed and the method gets called. Any clues?
tx in advance.
[]s

Change
<s:button action="#{abastecimentoAction.pesquisaAbasatecimentos}" id="pesquisaAbastecimentos" value="Pesquisar Abastecimento">
</s:button>
to
<h:commandButton action="#{abastecimentoAction.pesquisaAbasatecimentos}" id="pesquisaAbastecimentos" value="Pesquisar Abastecimento">
</h:commandButton>
The reason its not working is because <s:button> performs a HTTP GET, and does not POST your form.
You should also change int to Integer if it doesn't work.

Related

Neither BindingResult nor plain target object for bean name xxx available as request attribute

"Neither BindingResult nor plain target object for bean name 'loginCommand' available as request attribute"
I keep getting this Binding result error and nothing I've tried seems to be making it stop. I've seen other posts for this question, but none of them seem to fix whatever issue I'm having.
This is the first controller of my new project and I had some issues getting the xml squared away. I think that's all fixed, but if nothing looks off I supposed the problem could be there. The weird thing is that all this code is almost straight copied from another project I have and it works just fine.
Also I'm running on glassfish if that matters at all. Thanks in advance!
edit: The webpage is /morencore/login.jsp. I tried going to login.html assuming that would bring it up, but it only seems to work when I go to login.jsp. I believe I tried changing my controller to map to the jsp instead, but that did not work.
here is my login.jsp page:
<form:form method="post" modelAttribute="loginCommand">
<form:errors cssClass="error" element="p" />
<table border="0">
<tr>
<td align="right">Username:</td>
<td><form:input path="userName" /> <form:errors path="userName" cssClass="error" /></td>
</tr>
<tr>
<td align="right">Password:</td>
<td><form:password path="password" /> <form:errors path="password" cssClass="error" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" id="submit" name="submit" value="Log In" disabled="disabled"></td>
</tr>
</table>
</form:form>
and here is my controller:
#Controller
#ControllerAdvice
#RequestMapping("/login.html")
public class LoginController {
protected final Logger logger = LogManager.getLogger(getClass());
#Autowired
protected LoginValidator loginValidator;
#RequestMapping(method= RequestMethod.GET)
protected String initializeForm(#ModelAttribute("loginCommand")LoginCommand loginCommand,
BindingResult result,
ModelMap model)
{
logger.info("INITIALIZING LOGIN FORM");
model.addAttribute("loginCommand", new LoginCommand());
return "login";
}
#InitBinder("loginCommand")
protected void initBinder(ServletRequestDataBinder binder) throws Exception
{
binder.addValidators(loginValidator);
}
#RequestMapping(method=RequestMethod.POST)
protected String onSubmit(#ModelAttribute("loginCommand")LoginCommand loginCommand,
BindingResult result,
HttpServletRequest request) throws Exception
{
logger.info("validating login input");
loginValidator.validate(loginCommand, result);
if (result.hasErrors())
{
result.reject("login.failure");
return "login";
}
UserDao userDao = new UserDao();
User user = userDao.by_name(loginCommand.getUserName());
if (user == null
|| !user.getName().equals(loginCommand.getUserName())
|| !user.getPassword().equals(loginCommand.getPassword()))
{
result.reject("login.failure");
return "login";
}
return "redirect:main.html";
}
}
Here is my LoginCommand class:
#XmlRootElement
public class LoginCommand
{
private String userName;
private String password;
/** blah blah blah getters and setters*/
}
Here is the full stack trace as requested:
Neither BindingResult nor plain target object for bean name 'loginCommand' available as request attribute
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'loginCommand' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:142)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:154)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.autogenerateId(AbstractDataBoundFormElementTag.java:141)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.resolveId(AbstractDataBoundFormElementTag.java:132)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:116)
at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:422)
at org.springframework.web.servlet.tags.form.InputTag.writeTagContent(InputTag.java:142)
at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:84)
at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:80)
at org.apache.jsp.login_jsp._jspx_meth_form_input_0(login_jsp.java:233)
at org.apache.jsp.login_jsp._jspService(login_jsp.java:126)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:111)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:411)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1580)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:338)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.glassfish.tyrus.servlet.TyrusServletFilter.doFilter(TyrusServletFilter.java:305)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:250)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:652)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:591)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:463)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:168)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:242)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
Among other things, it seems like your mappings need to be modified. Here is what I would try. There are a lot of adjustments so no guarantees on whether it will work completely, but it should get you in the right direction.
#Controller
public class LoginController {
protected final Logger logger = LogManager.getLogger(getClass()); //look at SLF4J instead. Then you're not tied to a specific logger and you use a facade.
#Autowired //may want to use constructor wiring instead on these
private LoginValidator loginValidator;
#Autowired
private UserDao userDao; //this should be wired and not simply instantiated - Spring won't know about it otherwise
#Autowired
private LoginValidator loginValidator;
#GetMapping("/login")
public String initializeForm(Model model) {
logger.info("INITIALIZING LOGIN FORM");
model.addAttribute("loginCommand", new LoginCommand());
return "login";
}
#PostMapping("/loginPost")
public String onSubmit(#ModelAttribute("loginCommand") LoginCommand loginCommand,
BindingResult result) throws Exception {
logger.info("validating login input");
loginValidator.validate(loginCommand, result);
if (result.hasErrors()) {
result.reject("login.failure");
return "login";
}
User user = userDao.by_name(loginCommand.getUserName());
if (user == null
|| !user.getName().equals(loginCommand.getUserName())
|| !user.getPassword().equals(loginCommand.getPassword())) { //you should really refactor this and move it outside of your controller. Just keep routing code in your controller, not logic
result.reject("login.failure");
return "login";
}
return "main"; //you should return just "main" or redirect:/main depending on what you're trying to do - you want the JSP to be processed. Leaving off the extension allows you to change frameworks without changing the server-side code and allows the page to be compiled. You could switch to Thymeleaf, for example, and not touch any of this code.
}
}
Add an action to your form:
<form:errors cssClass="error" element="p" />
<table border="0">
<tr>
<td align="right">Username:</td>
<td><form:input path="userName" /> <form:errors path="userName" cssClass="error" /></td>
</tr>
<tr>
<td align="right">Password:</td>
<td><form:password path="password" /> <form:errors path="password" cssClass="error" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" id="submit" name="submit" value="Log In"></td>
</tr>
</table>
For the next developer reading your code, I'd rename LoginCommand to something closer to what it actually is - like UserDetailsAdapter or something along those lines. I am assuming that LoginCommand will implement UserDetails from Spring Security if you're using that.
You may also want to consider updating your UserDao to have the method called findOneByUsername instead of by_name. The naming convention can help you later when you use Spring Repositories.
Lastly, look at Project Lombok for your beans. It'll save you lots of headaches.

Java spring post form one to many relationship

I'm trying to get POST form data on controller of the object have one to many relationship. Like below code
My Notification Model
private long id;
#NotBlank(message = ERROR.NOT_EMPTY)
private String title;
#NotBlank(message = ERROR.NOT_EMPTY)
private String content;
// One Notification has many User
private List<NotificationUser> listNotificationUser;;
// Getter and setter method
My controller
#RequestMapping(value = "notification/add", method = RequestMethod.GET)
public String create(ModelMap model) {
ArrayList<User> listUser = userService.getAllUsername();
model.put("user", listUser);
model.addAttribute("notification", new Notification());
return "notification/add";
}
#RequestMapping(value = "notification/add", method = RequestMethod.POST)
public String create(ModelMap model, HttpServletRequest request,
#Valid #ModelAttribute(value = "notification") Notification notification, BindingResult bindingResult) {
....
}
My .jsp
<form:form method="POST" action="add" name="addForm" commandName="notification">
<!-- Other input -->
<form:select path="listNotificationUser" multiple="multiple" id="name" name="itemValue">
<form:options />
<form:options items="${user}" itemValue="id" itemLabel="name" />
</form:select>
<!-- Other input -->
</form:form>
When I submit POST form to controller, the field notification.listNotificationUser always is null (other field is fine).
I was search and try some solution but it not working.
I guess your problem its you have a typo in your form:select. You are defining 2 options blocks, and I guess you want to define just an empty option. So should be like this
<form:select path="listNotificationUser" multiple="multiple" id="name" name="itemValue">
<!-- Some value you can identify as empty option-->
<form:option value="0" label="--Options--"/>
<form:options items="${user}" itemValue="id" itemLabel="name" />
</form:select>

Getting null values from checkboxes

I am working on a simple Spring MVC project. I am having trouble getting values from checkboxes. What I mean is when a user checks 2 boxes out of 3, all 3 are binded to a list with non-checked values as null. That's wrong. I just want values that are checked. Those that didn't get checked should not come to list at all.
This is a snippet of my code:
POJO:
public class Student{
private List<StudentCourses> sc;
//getters and setters
}
public class StudentCourses{
private int courseID;
private String courseName;
private Character grade;
private String semesterID;
//getters and setters
}
This is what I send from my controller:
#RequestMapping(value = "/selectclasses", method = RequestMethod.POST)
public String selectClasses(Model m) {
Student s = new Student();
List<StudentCourses> coursesList = new ArrayList<StudentCourses>();
coursesList.add(new StudentCourses("Eng 101", '-', "SP 16"));
coursesList.add(new StudentCourses("Math 140", '-', "SP 16"));
coursesList.add(new StudentCourses("CS 442", '-', "SP 16"));
m.addAttribute("coursesList", coursesList);
m.addAttribute("student", s);
return "selectclasses";
}
This is what I have in my selectclasses.jsp:
<form:form modelAttribute="student" method="post" action="/success">
<table>
<c:forEach items="${coursesList}" var="r" begin="0" varStatus="status">
<form:checkbox path="sc[${status.index }].courseName" value="${r.courseName}" label="${r.courseName}" />
</c:forEach>
</table>
<input type="submit" id="submit" name="submit" value="Submit" />
</form:form>
I don't know why null is passed to the "sc.courseName" when it's not checked. What am I doing wrong? Or is there a work around it?
Please help
Thanks.
simply writer
<input type="checkbox" value="${r.courseName}" id="id"name="name"/>
in controller class get the values using
String []values=request.getParameterValues(pass the id);
simple you get the selected values
I found the Solution!
I found two ways to solve it. This is the solution using Spring tags:
<form:checkboxes path="sc" items="${coursesList}" itemValue="courseName" itemLabel="courseName" />
In the above code, itemValue and itemLabel is the main thing! itemValue and itemLabel simply refer to bean properties of an object inside items attribute (items="${coursesList}"). In a nutshell, if you need to use a List of your Custom Beans as the items attribute you need to use also the itemValue and itemLabel attributes. This bold part of paragraph is taken from: https://stackoverflow.com/a/15529281/4828463 by #Carlos Gavidia
And now the solution using JSTL core tags:
<c:forEach items="${coursesList}" var="courses">
<tr>
<td><form:checkbox path="sc" value="${courses.courseName}" label="${courses.courseName}"/></td>
</tr>
</c:forEach>
Again the value and label attributes are important.

Thymeleaf - how to use Hashmap

I'd like to use HashMap as List has been used in following example: http://www.thymeleaf.org/doc/thymeleafspring.html#dynamic-fields
I've tried however without effect.
Edit: I'm providing some code. So the problem is that I'd like to use hashmap products in the form, the example I've provided above works great with a list, however I'd like to use it with hashmap.
Entity:
#Entity
#Table(name = "meals")
public class Meal extends BaseEntity{
#NotEmpty
private String name;
#NotEmpty
private String recipe;
private String image;
private double cost;
#NotNull
private int kcal;
#NotNull
private int proteins;
#NotNull
private int fats;
#NotNull
private int carbs;
#NotNull
private int portions;
#ElementCollection
#Column(name = "quantity")
private Map<Product, Integer> products = new HashMap<>();
//getters & setters
Form:
<!DOCTYPE html>
<html lang="en">
<head th:replace="fragments/headTag :: headTag"/>
<body>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"></div>
<h2 th:text="#{meals.new.title}"/>
<form th:object="${meal}" th:method="post" th:action="#{${#httpServletRequest.servletPath}}"
enctype="multipart/form-data"
class="form-horizontal" id="newMealForm">
//other fields
<div class="control-group" th:classappend="${#fields.hasErrors('products')} ? error">
<label class="control-label" th:text="#{meals.products}"/>
<div class="controls"><span class="help-inline"
th:errors="*{products}">[error]</span>
<table class="table table-striped">
<thead>
<tr>
<th th:text="#{product.name}"/>
<th th:text="#{product.quantity}"/>
<th><button type="submit" name="addProduct" th:text="#{meals.addProduct}"/></th>
</tr>
</thead>
<tbody>
<tr th:each="products,rowStat : *{products}">
<td><input type="text" th:field="*{products[__${rowStat.index}__].value}" /></td>
<td>
<input type="number" th:field="*{products}" />
</td>
<td>
<button type="submit" name="removeProduct"
th:value="${rowStat.index}" th:text="#{meals.removeProduct}"/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary" th:text="#{submit}"/>
</div>
</form>
</div>
<div th:replace="fragments/footer :: footer"></div>
</body>
</html>
Controller methods to add/remove row:
#RequestMapping(value="/meals/new", params={"addProduct"})
public String addProduct(final Meal meal, final BindingResult bindingResult) {
meal.getProducts().put(new Product(), 1);
return "/meals/new";
}
#RequestMapping(value="/meals/new", params={"removeProduct"})
public String removeRow(
final Meal meal, final BindingResult bindingResult,
final HttpServletRequest req) {
final Integer rowId = Integer.valueOf(req.getParameter("removeProduct"));
meal.getProducts().remove(rowId.intValue());
return "/meals/new";
}
Error I've got is:
org.springframework.beans.InvalidPropertyException: Invalid property 'products[0]' of bean class [org.cybuch.incessantfeasting.model.Meal]: Invalid index in property path 'products[0]'; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'org.cybuch.incessantfeasting.model.Product' for property 'null'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type org.cybuch.incessantfeasting.model.Product for value '0'; nested exception is java.lang.IllegalArgumentException: Unable to parse '0'
I've solved this problem some time ago, so I guess it would be nice to share with the solution. I've changed map to list in controller with a wrapper, so it was List where ProductQuantity class contains 2 fields - Product product and String quantity. After that I'm converting that list to map and save to the database.

Spring mvc, how to bind a domain object that has a collection as its property

I have a domain object called Order, and it has a collection attribute called serviceOrders where a collection of service --- order m:m association relationships are hold.
public class Order implements Serializable {
private Long id = null;
private BigDecimal amountPaid;
private BigDecimal accountReceivable;
private User user;
private Set serviceOrders = new HashSet();
private Date closed;
private Date created = new Date();
private String status;
also there is a method for adding the association called addServiceOrder
public void addServiceOrder(ServiceOrder serviceOrder) {
if (serviceOrder == null)
throw new IllegalArgumentException("Can't add a null serviceOrder.");
this.getServiceOrders().add(serviceOrder);
}
how should I use commandName to set this collection with "path", I think it would only call its get set method of the Command Object. how should I add serviceOrder to this command Object. I have no idea about this problem. any help would be highly appreciated
Assuming your ServiceOrder instances have unique ids your service method should be #add(Long id).
Ok bear with me on this one but the solution is simple an annoying at the same time. I ran into this a couple of months ago. I am going to show you my solution using the jstl libraries in my view for handling the collections.
<c:forEach items="${Questions}" var="quest" varStatus="itemsIndex">
<fieldset>
<legend>${quest.section}</legend>
<form:form id="group${itemsIndex.index}" modelAttribute="ChoiceList" action="" method="POST" onsubmit="javascript:ajaxSave($(this).serialize()); return false;">
<a id="Group${quest.id}"></a>
<c:forEach items="${quest.qisQuestionsCollection}" var="quest2" varStatus="itemsRow">
<div style="font-weight: bold; margin: 10px 0px">${quest2.shortText}</div>
( ${quest2.qisQuestionTypes.description} )<br/>
( ${quest2.helpText} )<br/>
<a id="Question${quest2.id}"></a>
<c:choose>
<c:when test="${quest2.qisQuestionTypes.questionType == 'CHOOSEANY'}">
<c:forEach items="${quest2.qisChoicesCollection}" var="quest3" varStatus="indexStatus">
<c:forEach items="${ChoiceFields}" var="CField">
<c:set scope="request" value="${quest3}" var="ChoiceData"/>
<c:set scope="request" value="${CField}" var="ChoiceProperty"/>
<%
answerMap = (HashMap<QisChoice, Answer>) request.getAttribute("AnswerList");
choice = (QisChoice) request.getAttribute("ChoiceData");
if (answerMap.containsKey(choice.getChoiceID())) {
Answer theAnswer = (Answer) answerMap.get(choice.getChoiceID());
if (theAnswer != null) {
if (theAnswer.getChoiceValue() != null) {
request.setAttribute("itemValue", theAnswer.getChoiceValue());
request.setAttribute("itemSelected", true);
} else {
request.setAttribute("itemSelected", false);
request.setAttribute("itemValue", getReflectedValue(
(QisChoice) request.getAttribute("ChoiceData"),
(AccessorStruct) request.getAttribute("ChoiceProperty")));
}
}
} else {
request.setAttribute("itemSelected", false);
request.setAttribute("itemValue", getReflectedValue(
(QisChoice) request.getAttribute("ChoiceData"),
(AccessorStruct) request.getAttribute("ChoiceProperty")));
}
request.setAttribute("itemValue2", getReflectedValue(
(QisChoice) request.getAttribute("ChoiceData"),
(AccessorStruct) request.getAttribute("ChoiceProperty")));
%>
<c:choose>
<c:when test="${CField.visible == 'HIDDEN'}">
<form:hidden value="${itemValue2}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" />
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${itemSelected}">
<form:checkbox value="${itemValue}" label="${quest3.description}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" checked="true" /><br/>
</c:when>
<c:otherwise>
<form:checkbox value="${itemValue}" label="${quest3.description}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" /><br/>
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>
</c:forEach>
</c:forEach>
</c:when>
<input type="submit" value="Save Section"
class="button-main" />
</fieldset>
</form:form>
</c:forEach>`
The Key bit is in this line
<form:checkbox value="${itemValue}" label="${quest3.description}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" checked="true" /><br/>
To link up the command object with its collection for the postback you have to show the indice of the element as part of the spring path. In my case I have two levels of collections to track
<c:forEach items="${quest.qisQuestionsCollection}" var="quest2" varStatus="itemsRow">
varStatus gives you access to a bean object with the index property you can use to your advantage.
In your case you can do just use the index property of the foreach jstl function in the jsp to generate the indice like I did and append it to the array index notation of your command object. The command object must of course follow the same flow as the path collection names. This works for an infinite number of levels but gets more annoying as we go.
This is a large live example so if you need something smaller show me your markup and I will walk you throgh it.

Resources