Ответ 1
Мне нравится делать замену всей формы при возникновении ошибки. Ниже приведен пример супер примитивный. Я не собираюсь использовать тонну фрагментов для визуализации формы... просто сохраняя ее просто.
Это было написано в Spring 4.2.1 и тимелеафе 2.1.4
Основной класс, представляющий информационную форму пользователя: UserInfo.java
package myapp.forms;
import org.hibernate.validator.constraints.Email;
import javax.validation.constraints.Size;
import lombok.Data;
@Data
public class UserInfo {
@Email
private String email;
@Size(min = 1, message = "First name cannot be blank")
private String firstName;
}
Контроллер: UsersAjaxController.java
import myapp.forms.UserInfo;
import myapp.services.UserServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.transaction.Transactional;
@Controller
@Transactional
@RequestMapping("/async/users")
public class UsersAjaxController {
@Autowired
private UserServices userServices;
@RequestMapping(value = "/saveUserInfo", method = RequestMethod.POST)
public String saveUserInfo(@Valid @ModelAttribute("userInfo") UserInfo userInfo,
BindingResult result,
Model model) {
// if any errors, re-render the user info edit form
if (result.hasErrors()) {
return "fragments/user :: info-form";
}
// let the service layer handle the saving of the validated form fields
userServices.saveUserInfo(userInfo);
return "fragments/user :: info-success";
}
}
Файл, используемый для отображения формы и сообщения об успешности: fragments/user.html
<div th:fragment="info-form" xmlns:th="http://www.thymeleaf.org" th:remove="tag">
<form id="userInfo" name="userInfo" th:action="@{/async/users/saveUserInfo}" th:object="${userInfo}" method="post">
<div th:classappend="${#fields.hasErrors('firstName')}?has-error">
<label class="control-label">First Name</label>
<input th:field="*{firstName}" type="text" />
</div>
<div th:classappend="${#fields.hasErrors('first')}?has-error">
<label class="control-label">Email</label>
<input th:field="*{email}" ftype="text" />
</div>
<input type="submit" value="Save" />
</form>
</div>
<div th:fragment="info-success" xmlns:th="http://www.thymeleaf.org" th:remove="tag">
<p>Form successfully submitted</p>
</div>
Код JS просто передаст форму URL-адресу, указанному в атрибуте действия формы. Когда ответ возвращается на обратный вызов JS, проверьте наличие ошибок. Если есть ошибки, замените форму на ответ.
(function($){
var $form = $('#userInfo');
$form.on('submit', function(e) {
e.preventDefault();
$.ajax({
url: $form.attr('action'),
type: 'post',
data: $form.serialize(),
success: function(response) {
// if the response contains any errors, replace the form
if ($(response).find('.has-error').length) {
$form.replaceWith(response);
} else {
// in this case we can actually replace the form
// with the response as well, unless we want to
// show the success message a different way
}
}
});
})
}(jQuery));
Опять же, это всего лишь базовый пример. Как уже упоминалось выше, нет правильного или неправильного пути для этого. Это не совсем мое предпочтительное решение, есть определенно несколько хитростей к этому, я бы сделал, но общая идея есть.
ПРИМЕЧАНИЕ. В моем коде JS есть и недостатки. Если вы замените форму на ответ, обработчик отправки формы не будет применен к новой замененной форме. Вам нужно будет убедиться, что вы повторно инициализируете обработчик формы после замены формы, если собираетесь на этот маршрут.