我想知道使用 Javascript 和 Thymeleaf 动态添加表单元素最惯用/最佳的解决方案是什么。对于上下文,我有一个在服务器端生成的表单,如下所示:
<form
th:action="@{/some/path})}"
th:object="${pathBulletinForm}"
method="post"
class="mb-3 border rounded needs-validation"
novalidate
id="bulletinForm"
>
<select th:field="*{conditionRating}" type="select" id="conditionRating" name="conditionRating" class="form-select">
<option label="-- Select a Condition --" value=""></option>
<option th:each="pathConditionOpt : ${T(com.francisbailey.pathbulletin.persistence.model.PathCondition).values()}" th:value="${pathConditionOpt}" th:text="${pathConditionOpt.displayName}" th:attr="data-description='descriptionFor' + ${pathConditionOpt.name}"></option>
</select>
<a href="#" id="addConditionRating"><i class="bi bi-plus-circle"></i> Add Rating</i>
</form>
现在,我想做的是让用户单击一个按钮,它会自动将相同的
select
下拉列表附加到表单中。换句话说,他们可以在表单中附加多个“conditionRatings”。这在纯 javascript/客户端中很容易做到,但我喜欢在服务器端生成下拉列表,因为这些值来自枚举和单一事实来源。
我不确定最好的方法是什么。在 Javascript 中设置这个模板值看起来是可能的,但有点难看。
为了添加表单元素,我知道我可以执行以下操作:
<script>
const ratingButton = document.getElementById("addConditionRating");
const form = document.getElementById("bulletinForm")
ratingButton.addEventListener(e => {
form.appendChild(`<select>My Condition Ratings Template Here?</select>`);
});
</script>
但是,我不确定如何在那里设置实际的选择下拉菜单。我还需要将侦听器绑定到每个下拉列表,以在下拉列表下方显示服务器端呈现的描述/标签。
一种选择是将下拉代码放入片段中。 然后,您可以在页面中使用相同的代码,并添加另一个控制器方法以仅返回条件下拉列表。 例如这样的事情:
page.html
<head>
<meta charset="UTF-8"/>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script>
$(function() {
$('#addConditionRating').click(() => {
$.get('/condition',(data) => {
$('#conditionContainer').append(data);
});
});
});
</script>
</head>
<body>
<form
th:action="@{/some/path}"
th:object="${pathBulletinForm}"
method="post"
class="mb-3 border rounded needs-validation"
novalidate
id="bulletinForm"
>
<div id="conditionContainer">
<th:block th:replace="~{fragments :: condition}" />
</div>
<a href="#" id="addConditionRating"><i class="bi bi-plus-circle"></i> Add Rating</i>
</form>
</body>
fragments.html
<html>
<body>
<select th:fragment="condition" type="select" id="conditionRating" name="conditionRating" class="form-select">
<option label="-- Select a Condition --" value=""></option>
<option th:each="pathConditionOpt : ${T(com.francisbailey.pathbulletin.persistence.model.PathCondition).values()}"
th:value="${pathConditionOpt}"
th:text="${pathConditionOpt.displayName}"
th:attr="data-description='descriptionFor' + ${pathConditionOpt.name}"></option>
</select>
</body>
</html>
然后添加一个返回该页面片段的控制器方法:
@GetMapping("/condition")
public String condition() {
return "fragments :: condition";
}