java springframework <select> tag - spring

I am struggling with "SELECT/OPTIONS" tag. I have 2 ArrayList<<String>>: "pNames" and "pIds". Form should display "pNames", while the values returned to controller should be "pIds". From my spring controller I am passing the following 2 ArrayLists. How do I implement this in Spring MVC?
ArrayList<String> pIds = pps.getPIds();
ArrayList<String> pNames = pps.getPNames();
model.addAttribute("pIds", pIds);
model.addAttribute("pNames", pNames);
<form:select id="pps" name="pps" path="pIds" multiple="multiple">
<form:options items="${pIds}" itemValue="${pNames}" itemLabel="${pNames}"/>
</form:select>
Above code is not working.

You need to convert your Lists to a Map<String, String>. Then you can add the map to your model and you only need to do:
<form:select path="pIds">
<form:options items="${mapName}" />
</form:select>
For more information, please checkout this question: Use <form:select> tag with a map

Related

Spring MVC form not backed by a model object

I am pretty new to Spring MVC so please be easy on me.
I am having difficulties to understand how to achieve the following requirements in Spring MVC:
JSP list form, to list users from the database (service, repository thing are working properly).
Form is not backed by a model attribute object. This is a list/find form!
I need to list users matching some criteria taken from several "filter" fields like:
Region (dropdown list)
Is user archived? (yes/no dropdown list)
userList.jsp
<spring:url value="strFormAction" var="/rest/security/user/list" />
<form:form id="userListForm" method="GET" action="${strFormAction}" modelAttribute="user">
<form:select id="strRegionId" path="${strRegionId}" cssClass="form-control" onchange="updateUsersList('1');">
<spring:message var="strSelectRegionLabel" code="select.region" />
<form:option value="0" label="${strSelectRegionLabel}" />
<form:options items="${regions}" itemValue="intId" itemLabel="strNameFr" />
</form:select>
<form:select id="strArchived" path="${strArchived}" cssClass="form-control">
<spring:message var="strYesLabel" code="yes" />
<form:option value="true" label="${strYesLabel}"/>
<spring:message var="strNoLabel" code="no" />
<form:option value="false" label="${strNoLabel}"/>
</form:select>
<table>
...
<c:forEach items="${users}" var="user">
...rows generated here...
</c:forEach>
...
</table>
</form:form>
UserController.java
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String processUserList( #ModelAttribute("user") User user,
#RequestParam(value = "strRegionId", required = false) String strRegionId,
#RequestParam(value = "strArchived", required = false) String strArchived,
#RequestParam(value = "strSortBy", required = false) String strSortBy,
Model model) {
int intRegionId = strRegionId != null && strRegionId.equals("0") == false ? Integer.valueOf(strRegionId) : 0;
boolean booArchived = strArchived != null && strArchived.length() > 0 ? Boolean.valueOf(strArchived) : false;
int intSortBy = strSortBy != null && strSortBy.length() > 0 ? Integer.valueOf(strSortBy) : 1;
List<Region> regions = this.locationService.lstRegions();
model.addAttribute("strRegionId", String.valueOf(intRegionId));
model.addAttribute("strArchived", String.valueOf(booArchived));
model.addAttribute("strSortBy", String.valueOf(intSortBy));
List<User> users = this.securityService.listUsersByRegionAndArchiveState(intRegionId, booArchived, intSortBy);
model.addAttribute("user", new User());
model.addAttribute("users", users);
model.addAttribute("regions", regions);
return "user/userList";
}
It seems like I can't use the Spring form taglib at all without providing a modelAttribute in the form. I have then placed a dummy modelAttribute from my controller, but now I get:
javax.servlet.ServletException: javax.servlet.jsp.JspException: org.springframework.beans.NotReadablePropertyException: Invalid property '0' of bean class [spring4base.model.security.User]: Bean property '0' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
As I said earlier, that page is not meant to be backed by any specific POJO. This is a search page, that must return a list of users (User entity bean) based on filters selected previously (region, archived state). Form must submit on itself every time a dropdown is changed (user chooses a region, submit is done on the same mapping, and then the users list reloads with only users from that specific region).
I'm coming from Struts 1 in which we needed to create ActionForm for every single page. From what I read from the documentation, forms are not necessary these days so I am really looking forward into fixing that issue.
Any help would be greatly appreciated.
I would just create helper class containing your search criteria, for instance:
public class UserSearchCriteria {
private String regionId;
private Boolean archived;
private String sortBy;
// Getters and setters
}
Then I would modify your controller method like so (some code is missing, but this should give you the idea).
#RequestMapping(value = "/list", method = RequestMethod.GET)
public String processUserList(#ModelAttribute("searchCriteria") UserSearchCriteria userSearchCriteria, Model model) {
// Retrieve users and perform filtering based on search criteria
List<User> users = this.securityService.listUsers(searchCriteria);
model.addAttribute("users", users);
model.addAttribute("regions", regions);
return "user/userList";
}
And then you would use your filtering form like this:
<spring:url value="/rest/security/user/list" var="formAction" />
<form:form id="userListForm" method="GET" action="${formAction}" modelAttribute="searchCriteria">
<form:select path="regionId" cssClass="form-control" onchange="updateUsersList('1');">
<spring:message var="strSelectRegionLabel" code="select.region" />
<form:option value="0" label="${strSelectRegionLabel}" />
<form:options items="${regions}" itemValue="intId" itemLabel="strNameFr" />
</form:select>
<form:select path="archived" cssClass="form-control">
<spring:message var="strYesLabel" code="yes" />
<form:option value="true" label="${strYesLabel}"/>
<spring:message var="strNoLabel" code="no" />
<form:option value="false" label="${strNoLabel}"/>
</form:select>
You had several errors in the form in your snippet. For example the path attribute takes String containing name (or path) of the property to bind to, you were passing it some variable. Also you had value and var switched in your <spring:url> I think.
Try it, it's not complete solution but hopefully it will give you some directions on how to implement this. If you run into any problems, leave a comment and I'll update the answer.

Path attribute in form:select - spring 2.5 JSP

I've been put on the task of learning spring (2.5), and I've got into a problem using the attribute where, when the form is loaded, I wont get any pre-selected values. So the situation is as follows:
In my system I have Companies, Customers and Users. Customer extends Company, and a Company can have a List of Users (the getMethod is public so hence Customer also have a List of Users).
So this is how the form select looks in my .JSP:
<form:select multiple="true" id="selectAccountManager" path="${customer.users}" cssClass="input select_img" >
<c:forEach items="${customerUsers}" var="user" >
<form:option value="${user.id}
<c:out value="${user.displayName}" />
</form:option
</c:forEach>
</form:select>
Right now, I get an error on the path="${customer.users}". If I use path="users" my system works, but then I wont get any of the values within the form as "pre-selected" when the page loads. I've tried with path="customer.users" but when I do this I get a referenceError in js-console.
The .JSP is mapped to an EditCustomerController where customerUsers is put into a map by
map.put("customerUsers", UserControlHelper.getAllUsers());
So I guess this is where the problem lies as I always get all users from the system?
TL;DR: How do I set selected values on a form where I load the items from one class, and want the select-filter to come from another?
(First of all, Spring 2.5 is old and I suggest you to use 3.2.x or even 4.0.x)
To pre-select option you should set appropriate field on the model and Spring will pre-select it automagically. Like that:
<form:form method="post" modelAttribute="myForm">
<form:select multiple="true" path="users">
<form:options items="${customerUsers}" itemLabel="displayName" itemValue="id" />
</form:select>
</form:form>
And in the controller:
User defaultUser = new User(1, "DEFAULT");
MyForm myForm = new myForm();
myForm.getUsers().add(defaultUser);
model.addAttribute("myForm", myForm);
So I found out what the problem was.
When I created my map I only put the users in there. What the User-object actually was mapped upon was the id of the user (something I retrieved through ${user.id} as can be seen in the originalpost. What I had to do was to create the path in a correct way as such:
Controller - java:
Map<Int,String> users = new HashMap<Int,String>();
for(User user: UserControlHelper.getAllUsers()){
users.add(user.getId(), user.getDisplayName())
}
model.put("customerUsers", users);
and my jsp:
<form:select path="users" items="${customerUsers}"></form:select>

Simple JSP-Spring 3 dropdown list not working

I know this should be pretty easy but I'm stuck after trying several things.
I'm only trying to display in my jsp a basic dropdown list. Spring version is 3 so I want everything to work with annotations.
JSP form with dropdown list:
<form:form method="post" commandName="countryForm">
<table>
<tr>
<td>Country :</td>
<td><form:select path="country">
<form:option value="Select" label="Select" />
</form:select>
</td>
<tr>
<td colspan="3"><input type="submit" /></td>
</tr>
</table>
</form:form>
CountryForm.java is a plain object with a single String attribute "country", with its getters and setters.
Controller who deals with the GET request is the following:
#Controller
public class CountryFormController {
#RequestMapping(value = "MainView", method = RequestMethod.GET)
public String showForm(Map model) {
CountryForm cform = new CountryForm();
model.put("countryForm", cform);
return "MainView";
}
}
However, when I redirect to the JSP "MainView" I get the typical error:
org.apache.jasper.JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'countryForm' available as request attribute
org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:502)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:424)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
What am I doing wrong?
The select tag in the Spring TagLib needs to be provided with a collection, map or array of options. I'm not sure what you would like these to be so I will make some assumptions.
You need to include a collection, map or array of objects in your controller. Ideally you would have a Country class and create new instances for a set of countries. For the example to work with your code, I just created a static list of countries. Add the list to your model and then modify the select tag, setting the options to ${countries}. Assuming country is a field of type String on CountryForm with appropriate get/set methods, the country should data-bind to field when the form is submitted.
Controller
#Controller
public class CountryFormController {
#RequestMapping(value = "MainView", method = RequestMethod.GET)
public String showForm(Map model) {
List<CountryForm> cfs = new ArrayList<CountryForm>();
cfs.add("United States");
cfs.add("Canada");
model.put("countries", cfs);
model.put("countryForm", cform);
return "MainView";
}
}
JSP
<form:select path="countryForm.country" options="${countries}"/>
I have sample code at GitHub, try it an let me know. Look at landing.jsp and UserController
<form:select path="users[${status.index}].type" >
<form:option value="NONE" label="--- Select ---"/>
<form:options itemValue="name" itemLabel="description" />
</form:select>
HTH

Using object as key in map (treemap) in spring

I've tried to display on JSP page objects' properties from Map in FormBean. Map is defined as
Map<KeyObject, ValueObject> m
KeyObject has two properties
public class KeyObject implements Comparable<KeyObject> {
private Integer a;
private Integer b;
getters/setters/and rest basic methods
}
On JSP I want to obtain something like code below:
<c:forEach items="${formBean.m}" item="itm">
...
<form:input path="m[itm.key].propertyName" />
...
</c:forEach>
I need to:
display elements in proper order
submit objects to map
So is there any simple solution or I should do some "magic"?
Thanks for your time.
Stefan
Some more information. Each object will have other "view" so I try to use c:import
<c:forEach items="${formBean.m}" item="itm">
<c:import url=${itm.value.name}Page.jsp" />
</c:forEach>
and on ...Page.jsp I want to use form's inputs.
<c:forEach items="${formBean.m}" varStatus="itm">
<tr>
<td>${itm.key.propertyName}</td>
<td>${itm.value.propertyName}</td> <!--which is same as below ... -->
<td>${formBean.m[itm.key].propertyName}</td>
</tr>
</c:forEach>
You can iterate through the maps keys and values, like above, and output different fields as required.

SpringMVC - JSP Iteration Issue

I have the following class that I am attempting to use as a command object
public class Member {
private String datePeriod;
private String status;
private ArrayList <Project> projectList;
}
On the JSP, I would like the form to prefill with a pre-existing values.
<c:forEach items="${member.projectList}" var="project">
<tr>
<td><form:input path="**<var???>**" value="${project.projectEntry.projectDesc}" /></td>
</tr>
</c:forEach>
I am making an error with path which is causing an error in jsp. Does anyone know the proper syntax with regards to each iteration? Thanks.
My Spring MVC is bit rusty but if I remember correctly, path gets translated as the input name property in HTML eventually. So you can put any Label value in there and that should work.
<form:input path="ProjectDescription" value="${project.projectEntry.projectDesc}" type="text" />
This should get translated to:
<input name="ProjectDescription" type="text" value="<whatever_you_have_in_backing_bean>"/>
Do you want to look up name from a backing bean instead? If so you should be able to do something like below. Without knowing your data structure I am assuming it to be status.
<form:input path="member.status" value="${project.projectEntry.projectDesc}" type="text" />
More on the form tag here.

Resources