Accesssing model attribute in JPA doesn't work - java

I am having problems accessing a model attribute in my controller, using Spring.
When adding to the model, I write the status code as a key and the enumeration name as a value. The status code is e.g. AVAILABLE, NOTAVAILABLE, etc.:
String code = status.getCode();
String enumerationName = enumerationService.getEnumerationName(status, currentLocale);
model.addAttribute(code, enumerationName);
On my JPA page, I am trying to access the corresponding value using the key (status code, e.g. AVAILABLE):
<div data-availability>
<c:forEach items="${StockLevelDeliveryStatus.values()}" var="status">
<c:set var="textStyle" value="text-success" />
<c:if test="${status.code.toLowerCase() == 'notavailable'}">
<c:set var="textStyle" value="" />
</c:if>
<div class="d-none display-22 pb-2 ${textStyle}" data-availability-item data-${status.code.toLowerCase()}>
${status}
</div>
</c:forEach>
</div>
For example, the value of status is AVAILABLE and this is what is output in ${status}. However, I want the value AVAILABLE to be used as a key to return me the correct value that I set in the model above. If I change the ${status} statement to, say, ${AVAILABLE} instead, which is the concrete key, the appropriate value from the model is returned:
<div class="d-none display-22 pb-2 ${textStyle}" data-availability-item data-${status.code.toLowerCase()}>
${AVAILABLE}
</div>
If I understand it correctly, then instead of passing the enum value as a key, I need to somehow teach Spring to search in the model for the appropriate key.
As recommended in one of the replies, I also tried writing the Map<StockLevelDeliveryStatus, String> directly into the model:
Map<StockLevelDeliveryStatus, String> statusMap = new HashMap<StockLevelDeliveryStatus, String>();
for (StockLevelDeliveryStatus status : StockLevelDeliveryStatus.values()) {
statusMap.put(status, enumerationService.getEnumerationName(status, currentLocale));
}
model.addAttribute("statusMap", statusMap);
And the JSP accordingly:
<div data-availability>
<c:forEach items="${StockLevelDeliveryStatus.values()}" var="status">
<c:set var="textStyle" value="text-success" />
<c:if test="${status.code.toLowerCase() == 'notavailable'}">
<c:set var="textStyle" value="" />
</c:if>
<div class="d-none display-22 pb-2 ${textStyle}" data-availability-item data-${status.code.toLowerCase()}>
${statusMap[status]}
</div>
</c:forEach>
</div>
Here it already fails when accessing the model, because with this approach I do not get any output on the JSP.
Does anyone have any ideas on how to make this work?

Why not simply put a Map<StockLevelDeliveryStatus, String> into the model? You could then simply use ${statusMap[status]}.

Related

How to display a Set property in a spring form?

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>

How to handle buttons with same value but different names in Spring

I have a table that is dynamically created that has rows of movies.
It has a title column,
a media type column,
a rating column,
and a column that contains a "view" button.
When one of these view buttons is clicked,
I would like to go to a page that contains all the details of that movie by sending the title to the controller so I can query for it in mySql.
The problem is that for all these buttons,
the value is always going to be "view".
So my solution is to make the name of the button different as shown in the code below (this is the raw html generated from the jsp):
<html>
<body>
<form action="someAction">
<table>
<tr>
<th>title</th>
<th>type</th>
<th>rating</th>
</tr>
<tr>
<td>title1</td>
<td>DVD</td>
<td>R</td>
<td><input type="submit" name="mediaType.title1" value="view"></td>
</tr>
<tr>
<td>title2</td>
<td>DVD</td>
<td>R</td>
<td><input type="submit" name="mediaType.title2" value="view"></td>
</tr>
<tr>
<td>title3</td>
<td>BLU-RAY</td>
<td>PG-13</td>
<td><input type="submit" name="mediaType.title3" value="view"></td>
</tr>
</table>
</form>
</body>
</html>
I could then use a parameterMap to figure out which view was pressed.
That is messy and Spring has to have some way of being able to do this.
I thought something like this would work in the controller:
#RequestMapping("someAction", params = "mediaType.{title}=view")
public ModelAndView loadPage(String title) {
// use title to query mysql
// build Model
// return ModelAndView
}
However this doesn't work.
Is there something that I can use in Spring that would be simpler and cleaner like above instead of getting the parameterMap from the request?
If I'm understanding this correctly, you have rows of information organized into a table. You're looping through some kind of collection, which has the side effect of making each input field have similar 'name' attributes. As a result, it's difficult to determine which input fields you really care about. You've then chosen to use the button as an identifier (presumably, because only the one button you actually click on get's added to the request -all the others don't get submitted) to determine which 'row', and subsequent input fields.
I think this might all come down to which 'button' you're using. If you're using a literal input tag (type="submit" or "button") the 'value' attribute is what the user sees as the text on the button -so, you're forced to play shenanigans with the 'name' attribute (presumably by adding an index to the name, splitting the string once you get it out of the request, and using that identifier to get the other parameters out of the request that also have the same identifier appended to their 'name' attribute).
JSP
<input type="submit" name="view${varStatus.index}" value="View" />
HTML Source
<input type="submit" name="view3" value="View">
You should probably use the button tag instead. It allows the text that the user sees to be different than the value that is submitted in the request.
JSP
<button type="submit" name="view" value="${varStatus.index}" >View</button>
HTML Source
<button type="submit" name="view" value="3">View</button>
This gives you the 'identifier' for the row.
How Spring fits into this:
I played with the #RequestMapping and the #RequestParam annotations, and was unable to get Spring to give me the values directly into the controller. But, I was able to do it by writing a custom HandlerMethodArgumentResolver along with a custom annotation.
note: I'm using annotations and java config instead of xml config, AND probably more importantly -this was a quick and dirty example to get it working. adjust it as needed for your situation.
HandlerMethodArgumentResolver
Annotation
Controller method
Instead of putting the table inside one form, you could put multiple forms inside the table, in the TRs:
<tr>
<form action="someAction">
<td>title1<input type='hidden' name='title' value='title1' /></td>
<td>DVD</td>
<td>R</td>
<td><input type="submit" value="view"></td>
</form>
</tr>
Then each title has its own form and you send in the title (always with parameter name of title) from a hidden input.
The solution lies in this statement:
"I have a table that is dynamically created that has rows of movies".
Presumably,
you are looping through a list of movies and generating the table in the jsp file and each row has some unique identifier.
Add a hidden to identify the selected row.
Set the value of the hidden value in an onclick handler from the submit buttons.
Here is some example stuff:
<form ...>
<c:forEach blah var="row">
<tr>
...
<td><input type="submit" value="View" onclick="setSelectedRow('${row.id}')"/></td>
</c:forEach>
<input type="hidden" id="blammy" name="blammy" value=""/>
</form>
<script type="text/javascript">
function setSelectedRow(rowId)
{
... set blammy.value equal to rowId.
}
</script>
// the id is used by JavaScript to find the object in the DOM.
// the name is what appears in the request.
#RequestMapping("someAction")
public ModelAndView loadPage(
#RequestParameter("blammy") final String blammy)
{
...
}

Struts logic:iterate input field

I currently have the following code and the data is displayed fine.
<logic:iterate name="myList" id="product" indexId="iteration" type="com.mycompany.MyBean">
<tr>
<td> <bean:write name="product" property="weight"/> </td>
<td> <bean:write name="product" property="sku"/> </td>
<td> <bean:write name="product" property="quantity"/> </td>
</tr>
</logic:iterate>
But now I need to make the "quantity" part modifiable. The user should be able to update that field, press submit and when its sent to the server, "myList" should automatically update with the new quantities.
I've tried searching for help on this but all I keep finding is examples on how to display data only, not modify it. Any help would be appreciated.
So this is tricky, because there are many things to get done in order for it to work. First, declare your tags inside the iterator with the html tags, with attribute INDEXED=TRUE and an ID DIFFERENT THAN THE NAME, i also took out the "indexId" attribute to use the simple "index" word for the index:
<logic:iterate name="myList" id="myListI" type="com.mycompany.MyBean">
<tr>
<td> <html:input name="myListI" property="weight" indexed="true"/> </td>
<td> <html:input name="myListI" property="sku" indexed="true"/> </td>
<td> <html:input name="myListI" property="quantity" indexed="true"/> </td>
</tr>
after that, in order for struts to be able to get and set the attributes of your beans, you need to declare EXTRA get and set methods inside your collection object, using the name you wrote in the id of the iterate tag. In this case, you would write 2 extra get and set methods for the "myListI" :
public void setMyListI(int index, myBean value){
this.myList.add(value);
}
public myBean getMyListI(int index){
return this.myList.get(index);
}
I think Th0rndikes answer is mostly correct. My implementation is slightly different, so it might be worth trying this as well.
Form
private List<Parameter> activeParameters;
public List<Parameter> getActiveParameters() {
return activeParameters;
}
public Parameter getParam(int index){
return this.activeParameters.get(index);
}
JSP
<logic:iterate name="MyForm" property="activeParameters" id="param">
<tr>
<td><bean:write name="param" property="prompt"/></td>
<td><html:text name="param" property="value" indexed="true"/></td>
</tr>
</logic:iterate>
In summary, I didn't use Type in the iterate tag, using the property tag instead. In the bean adding a getter with matched the name of the iterate ID in the JSP (param) with an index as a method parameter did the trick.
Take a look at this: http://wiki.apache.org/struts/StrutsCatalogLazyList
Indexed Properties
Struts html tags have an indexed attribute which will generate the
appropriate html to populate a collection of beans when the form is
submitted. The trick is to name the id attribute to the same as the
indexed property.
For example the following jsp...
<logic:iterate name="skillsForm" property="skills" id="skills">
<html:text name="skills" property="skillId" indexed="true"/>
</logic:iterate>
...will generate the following html
<input type="text" name="skills[0].skillId value="..."/>
<input type="text" name="skills[1].skillId value="..."/>
....
<input type="text" name="skills[n].skillId value="..."/>
When the form is submitted BeanUtils will first call the
getSkills(index) method to retrieve the indexed bean followed by
setSkillId(..) on the retrieved bean.
Theoretically, the indexed attribute of the struts html tags could be used for this:
Valid only inside of logic:iterate tag. If true then name of the html tag will be rendered as "id[34].propertyName". Number in brackets will be generated for every iteration and taken from ancestor logic:iterate tag.
But, there is no corresponding indexed attribute on the html:errors tag, which limits its usefulness. Also, the required combination of id, name and property attributes can be rather confusing.
I found it easier to use jsp scriptlets to generate the property name including the iteration index. The following code requires that your form has a string array property "quantity".
<% int idx=0; %>
<logic:iterate ...>
<html:text property='<%= "quantity[" + idx + "]" %>'/>
<html:errors property='<%= "quantity[" + idx + "]" %>'/>
<% i++; %>
</logic:iterate>

Inconsistent Expression Language behaviour, same expression different values

The same EL expression ${taskId} gives two different values in different places.
I am using the Stripes framework, along with MongoDB and Morphia for Object-Mapping (and of course Java/JSP/etc).
Using the following JSP/Expression Language code:
<c:forEach items="${actionBean.tasks}" var="listTask">
<c:set var="taskId" scope="page" value="${listTask.id}"/>
<s:form method="post" beanclass="action.TaskActionBean">
${taskId}<s:hidden name="task.id" value="${taskId}"/>
<s:submit name="promoteTask" value="Up" />
</s:form>
</c:forEach>
Gives the following generated code:
<form method="post" action="/scrumyogi/">
4ef99b730364de7ec70dbd68
<input type="hidden" value="4ef99b6c0364de7ec70dbd67" name="task.id">
<input type="submit" value="Up" name="promoteTask">
<div style="display: none;">
<input type="hidden" value="NPNEJw6tUWfRBXf-vVOLTw==" name="_sourcePage">
<input type="hidden" value="XbfUDiSHGrU=" name="__fp">
</div>
</form>
As you can see ${taskId} is printing out 4ef99b730364de7ec70dbd68 and then 4ef99b6c0364de7ec70dbd67, which makes no sense to me, I need ${taskId} to print out the same value 4ef99b730364de7ec70dbd68 is the correct one.
Is there some known issue that could cause this.
EDIT: the real problem is that the ${taskId} within the hidden form tag is incorrect, I printed the other value to see what the expression contains, and then found that it's different in the different locations - which make things seriously confusing.
ActionBean code:
#UrlBinding("/")
public class TaskActionBean extends BaseActionBean{
String taskId;
Task task = new Task();
List<Task> tasks;
public final static String DISPLAY = "/index.jsp";
#DefaultHandler
public Resolution listTasks(){
tasks = Dao.datastore().find(Task.class).order("rank").asList();
return new ForwardResolution(DISPLAY);
}
public Resolution promoteTask(){
task.promoteTask();
tasks = Dao.datastore().find(Task.class).order("rank").asList();
return new ForwardResolution(DISPLAY);
}
// ... getters and setters
You have a taskId field in you action bean, and according to stripes taglib documentation:
The hidden tag assigns the value attribute by scanning in the following order:
for one or more values with the same name in the HttpServletRequest
for a field on the ActionBean with the same name (if a bean instance is present)
by collapsing the body content to a String, if a body is present
referring to the result of the EL expression contained in the value attribute of the tag.
So it probably finds the field in your action bean and takes the value from there.
The other (jsp el) ${taskId} is assigned from task list element.
Change the taskId to some name that doesn't coincide with your action bean field and it should work.

Use object's method in a jstl page

I have a model with this method:
public List<String> getPriviledgeNames()
I'm trying to display a list of checkbox in my jstl page, and I'd like to checked only the ones which their name is in the list returned from my model.
So I have something like:
<li>
<input type="checkbox" name ="priviledge" id="CheckBox2" class="checkbox" value="clickthrough" />
<label for="CheckBox2">Clickthrough</label>
</li>
<li>
<input type="checkbox" name ="priviledge" id="CheckBox3" class="checkbox" value="details" />
<label for="CheckBox3">Details</label>
</li>
I'd like to add the checked="checked" only their name is in the list provided by my model's method. Is there a way to do this WITHOUT using scriptlet? I'd like to have no java code inside my pages...
Thanks for any helps!
Roberto
<c:when test = "${fn:contains(list,value)}">
-according to the docs it's actually doing a string/string comparison, so I assume it's actually checking whether the string value is a substring of list.toString().
You could also do a manual test on each value in the list with a forEach tag but that would be messier.
By using a map instead of a list could do something like this:
<c:if test="${yourModel.priviledgeNames['clickthrough'] ne null}">
checked="checked"</c:if>
Or just this: ${yourModel.priviledgeNames['clickthrough']} by mapping your checkbox name to checked="checked"

Categories