How to display a Set property in a spring form? - java

I am working on a Spring MVC web app and I'm trying to figure out a way to display a property of type Set that is part of the entity in question. For the rest of the properties (String, boolean, int, etc) I can get away with the JSP file just using something like this to display them :
<li>
<label for="active">Active : </label>
<form:checkbox path="active" id="active" disabled="true"/>
<span><form:errors path="active" cssClass="error"/></span>
</li>
However, for a property of the entity which is a Set of other entities I cannot figure out how to display it. I'm thinking of using some sort of sub-table but I fiddled with it a lot with no success. I tried searching google and can't quite find what I need.
Thanks!
* New problem, but getting there! *
My OrderedMed class has a property of type StrengthUnit and I'm able to display its name using the method in the comments below :
<li>
<label for="meds[${loop.index}].strengthUnit.name">Strength Units : </label>
<form:input path="meds[${loop.index}].strengthUnit.name"/>
<form:errors path="meds[${loop.index}].strengthUnit.name" cssClass="error" />
</li>
However, I need this to be a drop-down that the user can change. My Med entity also has a property of type StrengthUnit and I'm able to accomplish what I want in its respective edit page by sending a list of all Strength Units from the controller and using the following code :
<select name="strengthUnit" path="strengthUnit.name" id="strengthUnit">
<option value="0" ${med.strengthUnit eq null ? 'selected' : ''}></option>
<c:forEach items="${strengthUnits}" var="strengthUnitSingle">
<option value="${strengthUnitSingle.id}" ${med.strengthUnit.name eq strengthUnitSingle.name ? 'selected' : ''}>${strengthUnitSingle.name}</option>
</c:forEach>
</select>
I'm trying to do the same thing with this entity and I cannot seem to make it work using the method suggested in the comments. I'm trying the below code :
<select name="strengthUnit" path="strengthUnit.name" id="strengthUnit">
<option value="0" ${meds[loop.index].strengthUnit eq null ? 'selected' : ''}></option>
<c:forEach items="${strengthUnits}" var="strengthUnitSingle">
<option value="${strengthUnitSingle.id}" ${meds[loop.index].strengthUnit.name eq strengthUnitSingle.name ? 'selected' : ''}>${strengthUnitSingle.name}</option>
</c:forEach>
</select>
Now i am getting this exception again :
javax.el.PropertyNotFoundException: Property '0' not found on type mdhis_webclient.entity.OrderedMed
I am using the same method to access the Set's index, what am I doing wrong?
Thanks!

You will probably need a forEach loop with the varStatus, example:
<c:forEach var="yourVar" items="${yourList}" varStatus="loop" >
<label for="yourVar[${loop.index}].something">Something ${loop.index + 1}</label>
<form:input path="yourVar[${loop.index}].someting" cssClass="form-control" autocomplete="off" />
<form:errors path="yourVar[${loop.index}].something" cssClass="text-danger" />
</c:forEach>

For the second part of my question, this is what i needed! I just needed a toString() method to my StrengthUnit entity (they should all have one anyway!)
<form:select name="strengthUnit" path="meds[${loop.index}].strengthUnit.name" id="strengthUnit">
<form:option value="0" label=""></form:option>
<form:options items="${strengthUnits}" />
</form:select>

Related

Spring boot [Thymeleaf]: EL1008E: Property or field 'category' cannot be found on object of type 'java.util.Optional'

I have a relationship between two tables product and product category. Now i want to Edit product.
I created a list, which when i click edit open another interface with product details plus Product category as an drop down, but i get an error on thymeleaf th:selected as i want it to display the drop down with the selected item in it, but i get error
EL1008E: Property or field 'category' cannot be found on object of type 'java.util.Optional'
Please help to resolve
I tried to change the select to input it works fine
<input type="text" class="form-control" id="name" name="name" th:field="<b>${update.category.ProductCategoryID}"</b> />
but using selected dont work
<select class="form-control" id="category" name="category">
<option
th:each="prodCat : ${prodCatList}"
th:value="${prodCat.ProductCategoryID}"
th:text="${prodCat.CategoryName}"
th:selected="${prodCat.ProductCategoryID} =={update.category.ProductCategoryID}">
</option>
</select>
Below is the code snip
<form th:object="${update}" th:action="#{/product/save}" method="post">
<div id="myForm">
....
<input type="text" class="form-control" id="name" name="name" th:field="${update.category.ProductCategoryID}" />
<select class="form-control" id="category" name="category">
<option
th:each="prodCat : ${prodCatList}"
th:value="${prodCat.ProductCategoryID}"
th:text="${prodCat.CategoryName}"
th:selected="${prodCat.ProductCategoryID} == ${update.category.ProductCategoryID}" <-- problem
>
</option>
</select>
<input type="text" class="form-control" id="ProdID" name="ProdID" th:field="${update.category.CategoryName}" />
It seems that Update is Optional and not an object, and the view received the Öptional rather than Update directly.
//something like this needs to be done when updating the model for this attribute
Optional<Update> update = <your code to get this in Java>
update.ifPresent(foundUpdateObject -> model.addAttribute("update", foundUpdateObject))
Thanks TechFree.
It work, I was doing a mistake where I am not taking the object from the Optional Class
Here is the code i put and it worked.
#GetMapping("/edit/{pctid}")
public String findOne(
#PathVariable(value = "pctid") Integer pctid,
Model model) {
model.addAttribute("prodCatList", productCategoryRepo.findAll());
productRepo.findById(pctid).ifPresent(o -> model.addAttribute("update", o));
// model.addAttribute("update",productRepo.findById(pctid));
return "/prod/edit";
}

Weird results of form:option in form:select

I am trying to preselect some values from a form:select tag. So, let's take a look at my sample class below:
public class Post
{
private boolean anonymize;
private boolean videoRequired;
/* getters, setters */
}
As you can see, there are two boolean fields. I'm using the first one in JSP like this:
<label>Anonymize</label>
<form:select path="anonymize" id="anonymize" class="form-control">
<form:option value="true" label="Yes" selected="${ (post.anonymize) ? true : ''}" />
<form:option value="false" label="No" selected="${ (!post.anonymize) ? true : ''}" />
</form:select>
which, when I inspect that element, results in (let's say that anonymize is true):
<select id="anonymize" name="anonymize" class="form-control">
<option selected="true" value="true">Yes</option>
<option value="false">No</option>
</select>
So far so good.
Now I do the EXACT same thing with my other boolean field videoRequired. First the JSP:
<label>Video required</label>
<form:select path="videoRequired" id="videoRequired" class="form-control">
<form:option value="true" label="Yes" selected="${ (post.videoRequired) ? true : '' }" />
<form:option value="false" label="No" selected="${ (!post.videoRequired) ? true : '' }" />
</form:select>
Which, results in (again, let's say that videoRequired is also true):
<label>Video required</label>
<select id="videoRequired" name="videoRequired" class="form-control">
<option selected="true" value="true">Yes</option>
<option value="false" selected="selected">No</option>
</select>
Take a look at this line:
<option value="false" selected="selected">No</option>
How can this even happen? I'm stuck with this for a few hours now, I have even tried with <c:choose> tag and then hardcoding the selected attribute - it gave me the exact same weird result. Can anyone please explain where have I gone wrong? I'm pulling my brains out since I'm doing the same thing on both fields, but still one works, the other one doesn't. Btw, when I take a look at mysql, both fields are properly set.
In order to pre-select a form:select element, you can set the corresponding variable anonymize to true in your controller method that returns your view.
#Controller
public String getForm(ModelMap model, Post post){
post.setVideoRequired(true);
return "view-name";
}

JasperException: equal symbol expected

I am using Spring form tag library & a select jquery plugin
An error occurs on running the jsp
org.apache.jasper.JasperException: /WEB-INF/view/home.jsp(51,4)
/WEB-INF/view/createpost.jsp(19,15) equal symbol expected
<li>
<form:select name="mood" class="selectpicker" data-style="btn-sm"
multiple data-width="100px" data-size="5" //Line 19
title='Feeling' path="mood">
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
</form:select>
</li>
<li>
<form:select name="Working" class="selectpicker" data-style="btn-sm"
data-width="110px" data-size="5" title='WorkingAt ..' path="WorkingAt">
<option value="1">A</option>
</form:select>
</li>
When I remove the multiple attribute from the first select tag, error disappears, but if effects the functionality. multiple attribute enables multiple value selection in the select tag.
Seems like spring form is not allowing multiple attribute to run.
Can anyone help on this?
I had the same issue when i try to add disebbled selected disabled after adding it like below problem got solved.
<form:option value="0" label="Membership Type" selected="true" disabled="true"/>
for your answer,
<option value="1" multiple="true">A</option>

The function " " must be used with a prefix when a default namespace is not specified

we are doing some weird handling of our form variables. Anyway I have managed to get the variables from the request so i can do some database stuff. Now i want to post back to the from so the select boxes are can be populated with the original selections.
Here is an example of a select field:
JSP:
Condition Code:
<select size="1" name="filterCriteria('CONDITION_CODE').values">
<option value=""> </option>
<c:forEach var="bean" items="${conditions}">
<option value="'${bean.code}'"<c:if test="${bean.code == form.filterCriteria('CONDITION_CODE').values}"> selected="selected"</c:if>>${bean.code}: ${bean.description}</option>
</c:forEach>
</select>
<input type="hidden" name="filterCriteria('CONDITION_CODE').fieldName" value="CONDITION_CODE"/>
<input type="hidden" name="filterCriteria('CONDITION_CODE').operation" value="="/>
As you can see the name is a function in the form: name="filterCriteria('CONDITION_CODE').values
Here is the form:
private String[] fieldNames;
private Map<String, FilterCriteriaForm> filters =
new HashMap<String, FilterCriteriaForm>();
public String[] getFieldNames() { return this.fieldNames; }
public Map<String, FilterCriteriaForm> getFilters() { return this.filters; }
public FilterCriteriaForm getFilterCriteria(String fieldName)
throws ServletException
{
FilterCriteriaForm filter = (FilterCriteriaForm)filters.get(fieldName);
if (filter == null)
{
filter = new DetFilterCriteriaForm( requestAction );
filters.put( fieldName, filter );
}
return filter;
}
public void setFilters(Map<String, FilterCriteriaForm> val) { this.filters = val; }
}
Anyway normally I do something like this on the jsp to set the field back to what is in the form: "<c:if test="${bean.code == form.filterCriteria('CONDITION_CODE').values}"> selected="selected"</c:if>
When I do this...I get this error:
The function filterCriteria must be used with a prefix when a default namespace is not specified
edit:
Condition Code: <select size="1" name="filterCriteria('CONDITION_CODE').values">
<c:set var="condition" value="filterCriteria('CONDITION_CODE').values" />
<option value=""> </option>
<c:forEach var="bean" items="${conditions}">
<option value="'${bean.code}'" <c:if test="${bean.code == param[condition]}">selected="selected"</c:if>>${bean.code}: ${bean.description}</option>
</c:forEach>
</select>
<input type="hidden" name="filterCriteria('CONDITION_CODE').fieldName" value="CONDITION_CODE"/>
<input type="hidden" name="filterCriteria('CONDITION_CODE').operation" value="="/>
<br/></br>
THIS IS WHAT WORKED....I looked at the form again closer...took out the single quotes and used the getFilters():
<select size="1" name="filterCriteria(CONDITION_CODE).values">
<option value=""> </option>
<c:forEach var="bean" items="${conditions}">
<c:set var="code" value="'${bean.code}'" />
<option value="${code}" <c:if test='${code == form.filters["CONDITION_CODE"].values[0]}'>selected="selected"</c:if>>${bean.code}: ${bean.description}</option>
</c:forEach>
</select>
Why are you giving your form and input elements invalid names like that?
Anyway, your concrete problem is that you're not comparing to a plain string, but to an EL object. As you have now, it expects a bean ${form} with a method filterCriteria(String) which returns some object which has a getValues() method. That's not what you want. You want it to be a plain string.
Fix it as follows, you need to quote it:
<c:if test="${bean.code == 'form.filterCriteria(\'CONDITION_CODE\').values'}">
But this won't let you achieve the functional requirement. It look like that you're confusing Java/JSP with JavaScript and expecting them to run in sync. This is not true, Java/JSP runs in webserver and generates HTML. JavaScript is part of HTML and runs in webbrowser only. The form variable is only available in JavaScript, not in a JSTL tag.
You actually need to grab the submitted value as a request parameter by ${param}. The values of all input elements are avaiable by their name in the request parameter map. It would look like follows:
<c:if test="${bean.code == param['filterCriteria(\'CONDITION_CODE\').values']}">
I only don't guarantee if that would work, I have never used names with invalid characters, you perhaps need to URL-encode the odd characters. It would be much easier if you give your form and input elements a valid name which matches the rules as per HTML specification.
<select name="condition">
<option value=""> </option>
<c:forEach items="${conditions}" var="condition">
<option value="${condition.code}" ${condition.code == param.condition ? 'selected' : ''}>${condition.code}: ${condition.description}</option>
</c:forEach>
</select>
(note that you had an invalid value in <option value>, those singlequotes doesn't belong there, I've removed them)
Update: as per the comments, you seem to have a EL syntax error problem when accessing the illegal parameter name in EL. The escape characters \ seems to be completely swallowed by the EL parser. Your best bet is probably to alias it with <c:set>:
<c:set var="condition" value="filterCriteria('CONDITION_CODE').values" />
...
<c:if test="${bean.code == param[condition]}">
Update 2: those singlequotes around the option value seem to be absolutely necessary. In that case, you need to add another alias on that. The full code would look like this:
<select size="1" name="filterCriteria('CONDITION_CODE').values">
<c:set var="condition" value="filterCriteria('CONDITION_CODE').values" />
<option value=""> </option>
<c:forEach var="bean" items="${conditions}">
<c:set var="code" value="'${bean.code}'" />
<option value="${code}" <c:if test="${code == param[condition]}">selected="selected"</c:if>>${bean.code}: ${bean.description}</option>
</c:forEach>
</select>

combo box in spring web mvc

I am using spring web mvc for my app's UI part..
By using following code, i am getting List Box where i can select more then 1 value..
<form:select path="domainsList">
<form:options items="${domainsList}" itemValue="domain" itemLabel="domain"/>
</form:select>
But I need a drop down combo box...
Can any one suggest how can i convert it to combo box ?
Thanks in advance..
Sorry, for asking silly question.. But i got working combo box by following code :
<form:select path="domainsList" multiple="false" size="1">
<form:options items="${domainsList}" itemValue="domain" itemLabel="domain"/>
</form:select>
</form:form>
Spring will decide the type of field to use depending on the type of data, so if the 'path' field is an object, it will show a dropdown, but if it is a "list" (array, collection, ...) it will show a list, unless you specify multiple="false"
This will show a list with multiple selection:
Integer[] ids;
<form:select path="ids" items="${whatever}" />
This will show a dropdown with single selection:
Integer id;
<form:select path="id" items="${whatever}" />
This will also show a dropdown with single selection:
Integer[] ids;
<form:select path="ids" items="${whatever}" multiple="false" />
The spring "form:select" tag just wraps the HTML select element. It also has an attribute size which has to be set to a value of 1 to let this selection become rendered as a combobox (in most browsers).
this is basic HTML:
http://www.w3.org/TR/html4/interact/forms.html#adef-size-SELECT
<form:select path="domainsList" size="1">
<form:options items="${domainsList}" itemValue="domain" itemLabel="domain"/>
</form:select>
#Nirmal please check your markup. This should work.
<html>
<SELECT name="selection" size="1">
<OPTION selected label="none" value="none">None</OPTION>
<OPTION label="1" value="1">OPTION 1</OPTION>
<OPTION label="2" value="2">OPTION 2</OPTION>
<OPTION label="3" value="3">OPTION 3</OPTION>
</SELECT>
</html>

Categories