Spring Thyme Leaf checking for global errors results in NPE - spring

To display global errors created with Spring MVC with Thyme Leaf, I tried the example given at http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#global-errors:
That, is:
<div th:if="${#fields.hasGlobalErrors()}">
and
<ul th:if="${#fields.hasErrors('global')}">
and
<div th:if="${#fields.hasGlobalErrors()}">
When I add them to my HTML, the page won't even render, nevermind about submitting the form. All the examples result in:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#fields.hasErrors('global')"
I tried this with v2.1.4 and v.2.1.3 and got the same error. Bug or am I doing something wrong?
Yes, the tags are all closed and properly formed. Yes, this code was within a form. Yes, all the other aspects of the form work without the global error check.
Here is a short version of broken HTML:
<form action="search.html" th:action="#{/auto/search}">
<p th:if="${#fields.hasErrors('global')}" th:errors="*{global}">
Incorrect date
</p>
<input type="text" th:field="${command.stockNumber}" />
<select th:field="*{command.startYear}">
<option value="" th:each="year : ${modelYears}" th:value="${year}"
th:text="${year}"></option>
</select>
</form>
And the controller..
#RequestMapping(value = "/auto/search", method = RequestMethod.POST)
public String search(#Validated
#ModelAttribute("command")
AutoSearchCommand autoSearchCommand
BindingResult result, Model model) {
return "search";
}

Solved:
th:object is needed in a tag preceding to the global error check. Unfortunately, this isn't mentioned in the Spring Thyme Leaf tutorial. Presumably, there's a default form name somewhere which I've overridden in my controller.
Adding the tag in results in this working html:
<form action="search.html" th:action="#{/auto/search}">
<div th:object="${command}" th:remove="tag">
<p th:if="${#fields.hasErrors('global')}" th:errors="*{global}">
Incorrect date
</p>
</div>
<input type="text" th:field="${command.stockNumber}" />
<select th:field="*{command.startYear}">
<option value="" th:each="year : ${modelYears}" th:value="${year}"
th:text="${year}"></option>
</select>
</form>
.. Where "command" is the name of the form bean in the controller.
This thread helped me figure it out.

Related

Spring Boot - Edit data

I did the get, post and delete method. But now I'm suffering to do the put method.
My controller:
#RequestMapping("/teste/equipe/editar/{id}")
public String update(#RequestBody Team newTeam ,#PathVariable("id") Long id)
{
Team team = teamService.findById(id);
team.setName(newTeam.getName());
team.setName(newTeam.getRole());
teamService.save(team);
return "redirect:/teste/equipe";
}
HTML:
<form action="/teste/equipe/editar/{id}" method="PUT">
<input type="text" th:field="${team.name}" placeholder="Nome">
<br>
<input type="text" th:field="${team.role}" placeholder="Função">
<button>
Enviar
</button>
</form>
Error:
Not certain this helps but the error on the whitelabel error page states:
Number Format Exception for input {id}
Seems like you're expecting {id} in your form:
<form action="/teste/equipe/editar/****{id}****" method="PUT">
to be interpolated with an actual ID. Should it instead be:
<form action="/teste/equipe/editar/${id}" method="PUT">

Thymeleaf + Spring. Using an object method instead another block in the form

I have a typical updateUser form built with Thymeleaf + Spring. I can list the user roles but I am trying to put these into a selectbox component. I am struggling with this line th:selected="${user.hasRole(role.role)}". Now, I know this component works and that is only a matter of access a boolean function to enable it. I am trying to reference a function of the form object using the select th:object. My syntax doesn't work. I have also try to access that function just like previous input tags would (only using the name without the object itself .ie username or in this case hasRole(). That doesn't work either.
<form th:object="${user}"
th:action="#{'/admin/usermanagement/adduser'} " method="post">
<div class="row">
<div class="col-md-3 form-group">
<label>Username:</label> <input type="text" class="form-control"
th:field="*{username}" />
</div>
</div>
<div class="col-md-3">
<h5>Roles :</h5>
</div>
<select class="js-example-basic-multiple" style="width: 75%"
name="froles" id="froles" multiple="multiple">
<option th:each="role : ${roles}" th:value="${role.role}"
th:selected="${user.hasRole(role.role)}"
th:text="${role.role}"></option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
In fact, my problem is types. th:selected="${user.hasRole(role.role)}" is a string and should be th:selected="${user.hasRole(role)}". I have both method in the domain object so that is fine.
th:value="${role.role}" is wrong for persistence. I want to return role but I get the following error message when I use role.role
codes [user.roles,roles]; arguments []; default message [roles]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property
and Java null exception when I use "${role}"

Can pass models to Spring, but Thymeleaf still indicates an error

My problem is that I can pass models between Thymeleaf and Spring, but Thymeleaf still indicates an error.
Spring code:
#GetMapping("{id}/edit")
String getEdit(#PathVariable Long id, Model model) {
postRepository.findById(id).ifPresent(o -> model.addAttribute("post", o));
return "edit";
}
#PostMapping("{id}/edit")
String postEdit(#ModelAttribute Post post) {
postRepository.save(post);
return "redirect:/";
}
Thymeleaf code:
<form th:action="|/${post.id}/edit|" th:method="POST" th:object="${post}">
<input type="text" th:value="*{title}" name="title">
<input type="text" th:value="*{content}" name="content">
<input type="submit" value="Edit">
</form>
Thymeleaf indicates that it can't resolve ${post.id}, *{title} and *{content}. I have stopped and rerun the application more times so I suppose something is amiss in my code, even if it works.
What should I do to solve this issue?
First of all I think you don't need path variable in post mapping. You can use post mapping without path variable. So try modifying you controller like
#PostMapping("/edit")
String postEdit(#ModelAttribute Post post) {
postRepository.save(post);
return "redirect:/";
}
If you write controller like this it will be easy defining path in thymeleaf.
And second error can't resolve *{title} and *{content} is because of invalid keyword. Please try modifying your thymeleaf like
<form th:action="#{/edit}" th:method="POST" th:object="${post}">
<input type="text" th:field="*{title}" name="title">
<input type="text" th:field="*{content}" name="content">
<input type="submit" value="Edit">
</form>
I think this will work as you are expecting.

Spring controller isn't binding data from html form

In my current spring-boot project, I have a form which data is handled by by this controller method:
#RequestMapping(value="alterar", method=RequestMethod.POST)
#ResponseBody
public void altera(#ModelAttribute("object") E object, BindingResult result) throws Exception {
serv.altera(object);
}
and this method call that one in the service class:
public void altera(E e) throws Exception {
settings.save_settings(e);
}
but when I try submit data through this controller, despite the browser's developer tools shows the fields are being sent to the server, no data is received by the controller (I saw both values for object and result.getModel(); for both, the value for the fields are null).
Anyone can see what I am doing wrong here?
ps.: the html for the form:
<form role="form" class="form" id="form" method="post" enctype="application/x-www-form-urlencoded" action="/Paypal/alterar">
<div class="field-box">
<label>http.ConnectionTimeOut</label>
<div class="col-md-7">
<input type="text" name="http_ConnectionTimeOut" class="form-control" value="" />
</div>
</div>
...
</form>
There is not model attribute defined in html form
Try updating your view as
<form role="form" class="form" id="form" method="post" enctype="application/x-www-form-urlencoded" action="/Paypal/alterar" modelAttribute="object">
Moreover modelattribute will just bind your whole class with one single object that is object here and will directly give the default value which is null. Try using #ResponseBody instead.

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.

Resources