Displaying “application-specific” validation errors in web UI using Thymeleaf's “fields.hasErrors”
-
30-06-2021 - |
Frage
I use Spring MVC together with Thymeleaf. I have an issue with Thymeleaf fields.hasErrors
which is as follows:
When a Bean Validation constraint error is raised (such as a @NotNull constraint), the following use of fields.hasErrors
works perfectly:
<span class="help-inline" th:if="${#fields.hasErrors('member.email')}" th:text="#{message_form.validation.email}"></span>
An error message is displayed OK next to the email field.
However, when an "application-specific" error (as opposed to Bean Validation constraint error) is raised by my code (see code from controller below),
// FROM SPRING MVC CONTROLLER
if (!registrationService.isEmailAvailable(registrationInfo.getMember().getEmail())) {
bindingResult.addError(new ObjectError("member.email", "email already used")); // TODO i18n
}
The th:if="${#fields.hasErrors('member.email')}"
does not evaluate to true and no error message is displayed....
The only way I have found to display those "application-specific" errors is to include the following underneath the form:
<div id="errors" class="alert alert-error">
<ul th:if="${#fields.hasErrors('*')}">
<li th:each="err : ${#fields.errors('*')}" th:text="${err}"></li>
</ul>
</div>
Then, it will display "email already used" as a list item.
Can anyone please clarify the behavior of th:if="${#fields.hasErrors('member.email')}"
and especially tell me why it will evaluate to false in the case of "application specific" errors?
Lösung
I found the solution to my isue: My problem comes from an incorrect usage of the Spring API.
I should be using a FieldError
instead of an ObjectError
.
So changing from:
//FROM SPRING MVC CONTROLLER
if (!registrationService.isEmailAvailable(registrationInfo.getMember().getEmail())) {
bindingResult.addError(new ObjectError("member.email", "email already used"));//TODO i18n
}
to
//FROM SPRING MVC CONTROLLER
if (!registrationService.isEmailAvailable(registrationInfo.getMember().getEmail())) {
bindingResult.addError(new FieldError("registrationInfo","member.email", "email already used"));//TODO i18n
}
solved the problem.