JSP form:checkbox into a c:foreach - java

Similar problems are invoked in many posts in this forum; but no one has a solution that specific one, I thank you for helping me in this :
I'm using spring to develop a web application,
I don't know what I should put in the path of the form:checkbox tag which inside the c:foreach one, here is my code :
<c:forEach items="${persons}" var="person" varStatus="i">
<tr>
<td><c:out value="${person.firstName}" /></td>
<td><c:out value="${person.lastName}" /></td>
<td><form:checkbox path="person.rights" value="Download"/>Download </td>
<td><form:checkbox path="person.rights" value="Delete"/>Delete </td>
</tr>
</c:forEach>
'rights' is a list of Strings as it defined in the spring documentation, it has a getter and a setter like the other properties, my checkboxes work outside the c:foreach tag, but when including them into this tag this exception is generated :
org.springframework.beans.NotReadablePropertyException: Invalid property 'person' of bean class [java.util.ArrayList]: Bean property 'person' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
do you have an idea about what the problem is ??

This problem is strangely undocumented on most places. Here is an extract from the links I am posting below. The gist is that we need a static placeholder which maps to the type instead of the value of the bean. So anything inside a ${} will not work out. For this, and in the specific case of using a JSTL loop operator <c:forEach> with s[ring form tld, we should refer to the type information in each iteration using the varStatus attribute of the <c:forEach> operator, just like indices of an array, and thus refer to the inner properties of the iterable collection using . on the collection variable accessible via the outermost bean backing up the form.
For example:
<c:forEach items="${teamslist_session.teams}" var="team" varStatus="teamsLoop">
<form:input path="teams[${teamsLoop.index}].name"/>
</c:forEach>
where:
teamList_session is the bean backing up the form
teams is the collection of beans the properties of which we need to set in the path attribute
var is the a reference to each member of the teams collection
teamsLoop is the iteration index, which is used in the line below to refer to the say, ith element's bean's property called name
Please refer to the following links for more information:
Forum Discussion - See the last post
The link provided for reference in link 1

Related

How to check classtype of a table field in thymeleaf?

I have a generic thymeleaf table as follows:
<tbody>
<th:block th:each="row : ${page.getContent()}">
<tr>
<td th:each="header : ${headers}" th:text="${row.__${header}__}"/>
</tr>
</th:block>
</tbody>
The table is simply backed by a list containing my domain objects:
List<Header> headers = List.of("firstname", "lastname");
List<Person> page;
What it does is: it loops my predefined list headers, and selects only those attributes defined in the headers list.
Question: how could I add an evaluation on the classtype of the extracted value of each field, so that I could apply a custom style in case of digits?
The problem is: when I output the class of the value that is shown, the output is a java.util.ArrayList always!
th:text="${{row.__${header}__}.class.name}"
Why doesn't this show the correct class of the td element?
You should be able to evaluate the header if you go down a level. My thought is that the preprocessor operation may not give you a reference to the header object on the same td element.
This use case may also be a good candidate for th:classappend since you may want to inherit some style.
Also, not sure whether it applies, but table headings are typically wrapped in a <thead> element. Then, I would assume you'd want a list of Person objects iterated in a <tbody>.
Haven't tested it, but try:
<thead>
<th:block th:each="header : ${headers}">
<th th:text="${header}" class="someClass" th:classappend="${header.name.class instanceof T(java.math.BigDecimal) ? 'someDigitClassStyle' : ''}" />
</th:block>
<thead>
Assumes use of Spring. Reference
Lastly, you can consider an Apache util for isNumeric if you want to more broadly catch digits.
Solution as follows to apply a specific css style based on instance check:
th:text="${row.__${header}__}"
th:style="${{row.__${header}__}.get(0) instanceof T(java.math.BigDecimal)} ? 'text-align:right' : ''"/>

Having exception in accessing a list through JSTL

I'm trying to access to a like this:
I pass to the JSP page
the list through request.setAttribute("list", list);
and try to access
<c:foreach items="${list}" var="element"}>
<li> ${element.name} ${element.price} </li>
</c:foreach>
but I get NumberFormatException. How can I access correctly the list?
If you select only a few columns from a table, JPA will return an array of objects for each row returned. i.e. it will return a List<Object[]> object. If you want to get back a list of Route objects you can write a constructor in the Route class that takes two values(name and pric and set the values appropriately in the constructor. You can then use the constructor in the JPA query like below to get Route objects:
select new yourpackage.Route(name, price) from Route
There are two issues in your JSTL:
<c:foreach items="${list}" var="element"}>
...
</c:foreach>
Its c:forEach not c:foreach.
There is one extra } in the end.
It should be like this:
<c:forEach items="${list}" var="element">
...
</c:forEach>
There are two option. Try any one as per need.
If the list contains Object[] then use ${element[0]}
If the list contains Route then use ${element['name']} or ${element.name} or ${element.getName()}. Make sure Route class contains name as instance variable with getter & setter methods.

JSTL nested forEach Lists throwing error

I am trying use JSTL on an old project where I have to use nested forEach.
My requirement is for example to iterate through a countries list, where each country will have a StateList which will contain State details.
<c:forEach items="${countryList}" var="country">
<c:out value="${country.name}" escapeXml="true" />
<c:forEach items="${country.StateList}" var="state">
<c:out value="${state.name}" escapeXml="true" />
</c:forEach>
</c:forEach>
When I try these I am getting error.
An error occurred while evaluating custom action attribute "items" with value "${country.StateList}": Unable to find a value for "StateList" in object of class "com.pack.Country" using operator "." (null)
What I am doing wrong? Is there a alternate method to do the same without using scriplets?
Issue Solved : The problem was that i used StateList instead of stateList as list name in class. Thanks.

Concatenating JSTL

I have a HashMap in the controller:
HashMap<String, ArrayList<String> map = new HashMap<String, ArrayList<String>();
In the JSP page I want to access this through something like this:
<c:forEach var="list" items="${requestScope.list}">
<c:set var="testing" value="{requestScope.map}"></c:set>
<c:forEach var="anotherTesting" items="${testing['${list.item}']}">
<option><c:out value="${anotherTesting}"/></option>
</c:forEach>
</c:forEach>
Where list.item is a String but it is used for another process but I want it to be used to access the HashMap.
Is there a way to concatenate JSTL? Either map.key or map['key'] will do.
I guess simply this would work:
<c:forEach var="anotherTesting" items="${testing[list.item]}">
<option><c:out value="${anotherTesting}"/></option>
</c:forEach>
Notice the difference with and without quotes:
${testing[list.item]} is equivalent to testing.get(list.getItem());
${testing['list.item']} is equivalent to testing.get("list.item");.
Some Note:
You don't need to specify the scope to access the attributes, unless there is a conflict with the same name in different scopes. So, "${requestScope.list}" can be changed to ${list}, and "${requestScope.map}" can be changed to ${map}.
Please use a different name for var attribute of outer loop. May be listItem instead of list.
No need to set the map to a different variable. That <c:set...> is not needed. You can directly access the property of map attribute.
So, your loop can be modified to:
<c:forEach var="listItem" items="${list}">
<c:forEach var="anotherTesting" items="${map[listItem.item]}">
<option><c:out value="${anotherTesting}"/></option>
</c:forEach>
</c:forEach>
The code in ${...} is not JSTL but Expression Language. You don't need to c̶o̶n̶c̶a̶t̶e̶n̶a̶t̶e̶ nest EL ${} expressions, just add it cleanly.
Knowing this, the expression ${testing['${list.item}']} will be ${testing[list.item]}.
BUT note that this is not what you really want/need unless testing is indeed a Map<String, ArrayList<String>>, otherwise you will get unexpected results. From your code above, assuming requestScope.list is a List<Map<String, ArrayList<String>>>, then the code would be:
<c:forEach var="listItem" items="${list}">
<c:forEach var="innerString" items="${map[listItem.item]}">
<option><c:out value="${innerString}"/></option>
</c:forEach>
</c:forEach>
Note that ${list} is the same as ${requestScope.list} assuming there's no list attribute nor in page, session or application scope, similar for ${map}.

How do I display action data in a JSP?

I am using an <s:iterator> tag in my JSP to display a List of people objects.
I tried creating ListOfPersons as a List in the action class, along with a getter and setter. I am still unable to display the data--how can I do it?
<s:iterator value="ListOfpersons" status="stat">
When I tried printing the size of list I am getting zero.
If I understood you right, you are having problem with expressing list using OGNL on JSP pages. You should name fields with YourListName[index].property format. Then OGNL will understand that you have a list called YourListName and its element at index have property with value which is on its input.
Please see example below:
<table>
<s:iterator value="ListOfpersons" status="status">
<tr>
<td><s:textfield name="ListOfpersons[%{#status.index}].firstname"/></td>
<td><s:textfield name="ListOfpersons[%{#status.index}].lastname"/></td>
<td><s:textfield name="ListOfpersons[%{#status.index}].age"/></td>
<td><s:textfield name="ListOfpersons[%{#status.index}].sex"/></td>
</tr>
</s:iterator>
</table>
Short Answer: store the information in the request and access it in the jsp.
Longer Answer:
Create some objects in the servlet (in your case, the action).
Store the objects in some JSP scope (HttpServletRequest.setAttribute()).
Forward (dispatch) the request to the JSP page (this is just struts config, you are already doing this).
In the JSP page, reference the variables (perhaps using a c:out tag or just use an EL expression in the JSP page text).
Some code (struts 1.x):
class Blah extends Action
{
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
{
... do stuff
request.setAttribute("Blammy", "Blammy Value");
... return some ActionForward.
}
}
In a JSP:
<span>The value of the Blammy variable is this here thing: ${Blammy}</span>
or
<span>The value of the Blammy variable is this here thing: <c:out value="${Blammy}"/></span>
Once you have the basic concepts down, just set a request attribute with the List in question and access it using the iterator tag in your JSP.

Categories