jQuery 处理 Thymeleaf Spring MVC AJAX 表单及其错误消息的推荐方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32196348/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Recommended way to handle Thymeleaf Spring MVC AJAX Forms and their error messages
提问by Kristof
What is the recommended way to handle AJAX forms and their error messages on the Thymeleaf side of things?
在 Thymeleaf 方面处理 AJAX 表单及其错误消息的推荐方法是什么?
I currently have a Spring controller which returns a JSON overview of fields and their respective error messages, but having to resort to using fully handwritten JQuery (or just regular Javascript) just feels a bit wrong, and slow; especially because of the large amount of forms I intend to have in the application.
我目前有一个 Spring 控制器,它返回字段的 JSON 概述及其各自的错误消息,但不得不求助于使用完全手写的 JQuery(或只是普通的 Javascript)只是感觉有点错误,而且速度很慢;尤其是因为我打算在申请中使用大量表格。
回答by yorgo
What I like to do is replace the entire form when an error occurs. The following is a super primitive example. I'm not going to use a ton of fragments for rendering a form... just keeping it simple.
我喜欢做的是在发生错误时替换整个表单。下面是一个超级原始的例子。我不会使用大量的片段来渲染表单......只是保持简单。
This was written in a Spring 4.2.1 and Thymeleaf 2.1.4
这是用 Spring 4.2.1 和 Thymeleaf 2.1.4 编写的
A basic class representing a user info form: UserInfo.java
代表用户信息表单的基本类: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;
}
The controller: UsersAjaxController.java
控制器: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";
}
}
The file used to render the form and the success message: fragments/user.html
用于呈现表单和成功消息的文件: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>
The JS code will simply submit the form to the URL provided in the form action attribute. When the response is returned to the JS callback, check for any errors. If there are errors, replace the form with the one from the response.
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));
Again, this is just a basic example. As mentioned in the comments above, there is no right or wrong way to go about this. This isn't exactly my preferred solution either, there are definitely a few tweaks to this I would do, but the general idea is there.
同样,这只是一个基本示例。正如上面的评论中提到的,没有正确或错误的方法来解决这个问题。这也不是我最喜欢的解决方案,我肯定会对此进行一些调整,但总体思路就在那里。
NOTE: There's a flaw in my JS code as well. If you replace the form with the one from the response, the form submit handler will not be applied to the newly replaced form. You would need to ensure you reinitialize the form handler properly after replacing the form, if going this route.
注意:我的 JS 代码也存在缺陷。如果您用响应中的表单替换表单,则表单提交处理程序将不会应用于新替换的表单。如果走这条路线,您需要确保在替换表单后正确重新初始化表单处理程序。
回答by Yepadee
Don't know if anybody's still interested, but I'll leave this here for the sake of anyone looking for an example solution.
不知道是否有人仍然感兴趣,但为了任何寻找示例解决方案的人,我将把它留在这里。
I implemented yorgo's solution and got around the "flaw" by including the script in the fragment. There was also another small flaw in that if there was more than one submit button with an extra parameter (which is often used to implement dynamic forms in spring + thymeleaf) the information is lost when the form is serialised. I got around this by manually appending this information onto the serialised form.
我实现了 yorgo 的解决方案,并通过在片段中包含脚本来解决“缺陷”。还有一个小缺陷是,如果有多个带有额外参数的提交按钮(通常用于在 spring + thymeleaf 中实现动态表单),则在表单序列化时会丢失信息。我通过手动将此信息附加到序列化表单上来解决这个问题。
You can view my implementation of yorgo's solution with the fixes here: https://github.com/Yepadee/spring-ajax/blob/master/src/main/resources/templates/project_form.html?fbclid=IwAR0kr_-t05_vFrPJxvbsG1Et7aLGir5ayXyPi2EKI6OHbEALgDfmHZ7HaKI
您可以在此处查看我对 yorgo 解决方案的实施以及修复程序:https: //github.com/Yepadee/spring-ajax/blob/master/src/main/resources/templates/project_form.html?fbclid=IwAR0kr_-t05_vFrPJxvbsG1Et7aLGir5ayXyPi2EgKID
Whats nice about it is that you can implement it on any existing thymeleaf form simply by doing the following:
它的好处是您可以通过执行以下操作在任何现有的百里香叶表单上实现它:
- put the script in the form and make it reference the form's id
- put the form into a fragment
- change the post methods in the controller to return the form fragment rather than the entire template
- 将脚本放在表单中并使其引用表单的 id
- 将表单放入片段中
- 更改控制器中的 post 方法以返回表单片段而不是整个模板
回答by bwfrieds
Very little documentation on this but if you are already familiar with Web Flow, you may not need more. I'm not sure how this technique works with normal bean binding in Thymeleaf. I would love to see a full pet-clinic demo app use this so I can see the controllers.
关于此的文档很少,但如果您已经熟悉 Web Flow,则可能不需要更多文档。我不确定这种技术如何与 Thymeleaf 中的普通 bean 绑定一起使用。我很想看到一个完整的宠物诊所演示应用程序使用它,以便我可以看到控制器。
回答by diafragment
Not sure if it could be considered as a best practice, but here is what I did:
不确定它是否可以被视为最佳实践,但这是我所做的:
Map<String, String> errorMap = binding.getFieldErrors()
.stream().collect(Collectors.toMap(
e -> e.getField(), e -> messageSource.getMessage(e, locale)));
Then I sent the map back into the ajax response to process in the "success" section.
然后我将地图发送回 ajax 响应以在“成功”部分进行处理。