JSTL: html snippet depending on property being null or not. (with not empty) - jstl

<c:forEach items="${list }" var="element">
<c:if test='${not empty element.radioelement}'>
<input type="radio" name="${element.name }" id="${element.id }" >
<label for="${element.id }"></label>
</c:if>
<c:if test='${not empty element.divelement}'>
<div> </div>
</c:if>
<c:if test='${not empty element.breakelement}'>
<br />
</c:if>
</c:forEach>
This is the jstl code I'm trying to find out if it works.
The list is filled with the objects of the class "tyle" which I made myself. These contain the following properties:
private String radioelement, divelement, breakelement, name, id;
I made sure they all have setters and getters.
I'm trying to make it work so that depending on which property isn't null, that piece of html will be written. (a radiobutton incase the string radioelement isn't null and so forth untill the list ends)
I'm wondering if this will work this way cus if it does I'll probably have a logical fault in my code. As it is now it only registers the breaks and makes any divelement also into a radio.

Related

Thymeleaf th:field doesn't bind the value for input text

I want to send an object to the view for presentation and send it back to controller using springboot and Thymeleaf, however, I encounter a weird problem with Thymeleaf's th:value.
This is my controller:
#GetMapping("/food/buy/{fid}")
public String buyFood(HttpServletRequest request, #PathVariable("fid") Long fid, Model model) {
Food food = consumerService.getFood(fid);
System.out.println("foodid = " + food.getId());
model.addAttribute("food", food);
model.addAttribute("order", new OrderVO());
return "user/direct/f_order";
}
and my view:
<form th:action="#{/user/buy/direct/food}" method="post" th:object="${order}">
<table border="1px">
<tr th:hidden="true">
<td><input type="text" th:value="${food.id}" th:field="*{fid}" th:readonly="true"></td>
</tr>
</table>
</form>
and the VO class:
public class OrderVO {
private Long fid, address;
private Integer amount;
#DateTimeFormat(pattern = "HH:mm")
private Date deliverTime;
}
the problem is, the input field's value is null, but I'm sure that the food's id is not null (I print it in the controller)
I remove the th:field block, and the food.id can be properly presented. If I add the th:field block back, the problem reoccur.
So there may be something wrong with th:field, but I can't figure out. Can somebody point out my mistake?
===========================UPDATE============================
Some friends kindly points out that th:field may overwrite th:value, but I also use them in other views and it works fine:
<tr>
<td>UserName</td>
<td><input type="text" th:value="*{userName}" th:field="*{userName}"></td>
</tr>
The problem is getting incresing weird I think :(
Replace *{fid} with fid
My team had this same issue and it worked
In tabualr form try using th:name instead of th:field to overcome th binding issue
th:name="|order.fid|"
and stick to java naming convention.
Supposing you have to collect a comment to a page. You must transmit to the controller, besides the comment, the name of the page. Ofcourse, the user don't have to re-enter the name of this page. This information must be passed to controller, but th:field only map the values entered by the user, not the values generated by default.
But you can transmit the name of this page to controller as parameter in URL.
In html, you have something like that:
<form th:action="#{/saveComment(lastPage=${lastPage})}" th:object="${comments}" method="post" enctype="multipart/form-data">
<div class="row">
.................................................................................
<h2>Enter your comment</h2>
<textarea th:field="${comments.comment}" rows="10" cols="100" name="comment" id="comment"></textarea>
<label for="comment">Your comment here</label><br />
<input type="submit" name ="submit" value="Submit" />
</div>
</form>
In controller, you put stuff like this:
#PostMapping("/saveComment")
public String saveComment(Comments comments, String lastPage) {
comments.setPage_commented(lastPage);
commentsRepository.save(comments);
return "redirect:/";
}
It works fine to me.

How to get values for dynamic form field names using JSTL and EL

I have 8 checkboxes and 1 button, when the user check any of the checkboxes and click the button, I want to check if any of the checkbox is checked and display it in another .jsp
I have already referred to few similar questions with no luck so far. So i tried to manage with my own logic
First.jsp
<c:forEach begin="1" end="8" varStatus="loop">
<input type="checkbox" id="seat" name="seat${loop.index}" value="seat${loop.index}" >
<label for="seat">Seat${loop.index}</label>
</c:forEach> <br> <br>
<input type="submit" value="Save" name="savebtn">
Second.jsp
<c:forEach begin="1" end="8" varStatus="loop">
<c:if test="${not empty param.seat[loop.index]}">
<c:out value="${param.seat1} is booked"/>
</c:of>
</c:forEach>
I have 2 problems regarding the code above :
i can't get loop.index value inside the param $param.seat[loop.index] doesn't work
And even if i try to do it manually, i can only get value from seat1. I can't get value from the rest ( seat2, seat3, etc).
${param.seat[loop.index]} implies that seat is a collection, which it is not (it probably does not even exist). You are after ${param.seatX}, where you can dynamically set X. You can do that by creating a variable containing the parameter name first:
<c:set var="seatVarName" value="seat${loop.index}"/>
Now you can use this variable to get the parameter value from the implicit EL object:
${param[seatVarName]}
See also:
JSP expression language and dynamic attribute names

Need to Combine Spring Binding Errors and Custom Exceptions into Same DIV

I need to display SpringMVC's Form errors, as well as any custom "Exception" messages that I store in the request, in the same DIV on my page.
Right now they're in separate DIV's:
<!-- Validation Errors -->
<spring:hasBindErrors htmlEscape="true" name="model">
<c:if test="${errors.errorCount gt 0}">
<div class="errors_div clsErrorTblBorder">
<c:forEach items="${errors.allErrors}" var="error">
<div class="errors clsWhiteBack blue">
<myForm:message messageLinkClass="errorLink"
error="${error}" />
</div>
</c:forEach>
</div>
</c:if>
</spring:hasBindErrors>
<!-- Exceptions -->
<c:if test="${fn:length(requestScope.exceptions) > 0}">
<div class="errors_div clsMsgTblBorder">
<c:forEach items="${requestScope.exceptions}" var="exception">
<div class="messages clsWhiteBack">
${exception}
</div>
</c:forEach>
</div>
</c:if>
The shared condition for an Error DIV should be,
${fn:length(requestScope.exceptions) || errors.errorCount gt 0}
But it's impossible to test this condition, because:
You don't get the errors var. until you do <spring:hasBindErrors>
Anything inside <spring:hasBindErrors> only applies if you have
binding errors. If you don't (e.g. if you only have a custom
Exception message) its logic won't execute, so you can't move the
custom "exceptions" check inside it.
I got some clues from this thread: How to access Spring 3 MVC validator results in JSP without using form taglib , and here's the working result:
<c:if test="${fn:length(requestScope.exceptions) > 0 ||
requestScope['org.springframework.validation.BindingResult.model'].hasFieldErrors()}">
The 2nd part of this condition checks for Binding Errors even prior to the tag Spring:hasBindErrors.

Form Submit using a Javascript to invoke webflow transition, doesn't take the updated value on form

I am trying to invoke a form submit using javascript (jquery) to invoke a webflow transition. It works and the submit invokes the desired transition. But, the updated radio button values is not reflected on the model object which is posted.
Here is the code:
<form:form method="post" action="#" commandName="infoModel" name="pageForm">
<form:input type="input" path="testMsg" id="success" />
<input type="button" id="clearSelections" value="Clear Selections">
<div class="question">
<h4><c:out value="${infoModel.questionInfo.description}"/> </h4>
<form:radiobuttons path="infoModel.answerId"
itemValue="answerId" itemLabel="answerDescription" items="${infoModel.answers}" delimiter="<br/>" />
</div>
<input type="submit" name="_eventId_saveQualitativeInput" value="Save" id="save" />
$(document).ready(function() {
$('#tabs').tabs();
//Clear selections (copy is server-side)
$('#clearSelections').click(function() {
//$('input[type="radio"]').prop('checked', false);
$('input[type="radio"]').removeAttr('checked');
$('#save').trigger('click');
});
});
</form:form>
The form:radiobutton, generates the below html:
<div class="question">
<h4>Is this a general obligation of the entity representing a full faith and credit pledge? </h4>
<span>
<input type="radio" checked="checked" value="273" name="infoModel.answerId" id="infoModel.answerId1">
<label for="infoModel.answerId1">Yes</label>
</span>
<span><br>
<input type="radio" value="274" name="infoModel.answerId" id="infoModel.answerId2">
<label for="infoModel.answerId2">No</label>
</span>
<br>
<span class="error"></span>
</div>
The input id= "success" value is registered and when the control goes to the server, the value of input id= "success" is updated in the "infoModel" object. But the value of answerId is not updated on the "infoModel" object.
Thoughts if i am missing something in the form:radiobutton element or if there is something else wrong?
Thanks in advance!
EDIT:::::::
Thanks mico! that makes sense. I stripped of some of the code first time to make it precise, but i have a list which is being used for building the radio-buttons, below is the code:
<c:forEach items="${infoModel.list["index"]}" var="qa" varStatus="rowCount">
<div class="question">
<h4><c:out value="${question.questionInfo.description}"/> </h4>
<form:radiobuttons path="list["index"][${rowCount.index}].answerId" itemValue="answerId" itemLabel="answerDescription" items="${question.answers}" delimiter="<br/>" />
<br>
</div>
</c:forEach>
Could you please suggest how i could try this one out?
NOTE: The same code works on a regular form submit on click of a button of type submit. Its the javascript form submit which is not working. I also tried to do whatever i want to do in javascript and then invoke the button.trigger('click'); form got submitted but the changes made on form in my javascript didnt reflect.
With commandName inside a form:form tag you set "Name of the model attribute under which the form object is exposed" (see Spring Documentation). Then in path you should tell the continuation of the path inside the model attribute.
With this said I would only drop the extra word infoModel from path="infoModel.answerId" and have it rewritten as path="answerId" there under the form:radiobutton.

Binding multiple objects in a Spring form

I have problems with getting my JSP view right. What I intend to do is to send a List that contains questions and each question object is a text field and a List with alternatives.
My intention is to be able to edit multiple questions (both to be able to edit the text/name of the question and edit the containing alternatives).
My backing object is now sending an List question.
Here is my JSP which are failing with invalid property of bean class.
<form:form commandName="question">
<form:errors path="*">
<fieldset class="stdframe">
<legend>Question</legend>
</fieldset>
</form:errors>
<div class="stdframe">
<c:forEach var="q" items = "${question}" varStatus = "s">
<p><b>Question:</b></p>
<p><form:input size="67" path="${q.text}"/></p>
<br/>
${q.text}
<ul>
<c:forEach var="alternative" items = "${q.alternatives}" varStatus = "t">
${alternative.text}
<li><form:input path = "${alternative[$t.index].text}" /></li>
</c:forEach>
</ul>
<br/>
</c:forEach>
<input type="submit" class="submit" value="Save" />
<input type="button" class="button" onClick="back()" value="Back"/>
</div>
</form:form>
I have tried both ${q.text} and ${q[$s.index].text}. When I just print ${q.text} it shows the correct text for the question object. Same goes for alternative.
What can I do to correctly bind the form to the objects?
In addition when I store an object which contains a list of other object, will the list be stored itself in the database?
You may need to wrap your List in a simple object with the List as a field:
class MyListWrapper { List questions; } // etc.
If you use that as your command/form object, you should be able to do something like this in the JSP:
<form:form commandName="wrapper">
// ...
<c:forEach var="q" items = "${wrapper.questions}" varStatus = "s">
<p><b>Question:</b></p>
<p><form:input size="67" path="questions[${s.index}].text"/></p>
// ...
<c:forEach var="alternative" items = "${q.alternatives}" varStatus = "t">
${alternative.text}
<li><form:input path = "questions[${s.index}].alternatives[${t.index}].text" /></li>

Resources