Spring中Thymeleaf+Bootstrap展示枚举值下拉不显示问题
问题:Thymeleaf结合Bootstrap展示枚举值时下拉菜单内容不显示(元素已生成)
相关代码
1. 领域模型类Events
@ToString public class Events { private long id; private static long nextId = 1L; @NotBlank(message = "name required") @Size(max = 50, message = "name too long") private String eventName; @NotBlank(message = "description required") @Size(max = 200, message = "description too long") private String eventDescription; @NotBlank(message = "email required") @Email(message = "invalid email address") private String emailAddress; private TypeOfEvents typeOfEvents; public Events(String eventName, String eventDescription, String emailAddress, TypeOfEvents typeOfEvents) { this.eventName = eventName; this.emailAddress = emailAddress; this.eventDescription = eventDescription; this.typeOfEvents = typeOfEvents; this.id = nextId; nextId = nextId + 1; } public Events(){} public long getId() { return id; } public String getEventName() { return eventName; } public void setEventName(String eventName) { this.eventName = eventName; } public String getEventDescription() { return eventDescription; } public void setEventDescription(String eventDescription) { this.eventDescription = eventDescription; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String getEmailAddress() { return emailAddress; } public TypeOfEvents getTypeOfEvents() { return typeOfEvents; } public void setTypeOfEvents(TypeOfEvents typeOfEvents) { this.typeOfEvents = typeOfEvents; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Events events = (Events) o; return Objects.equals(eventName, events.eventName) && Objects.equals(eventDescription, events.eventDescription); } @Override public int hashCode() { return Objects.hash(eventName, eventDescription); } }
2. 枚举类TypeOfEvents
public enum TypeOfEvents { SEMINAR("Seminar"), BOOTCAMP("Bootcamp"), CRASHCOURSE("Crashcourse"), LIVEMEETING("LiveMeeting"), GATHERING("Gathering"); private final String displayEventType; TypeOfEvents(String displayEventType) { this.displayEventType = displayEventType; } public String getDisplayEventType(){ return displayEventType; } }
3. Controller代码
// 访问localhost:8080/events/create时渲染创建表单视图 @GetMapping("create") public String renderCreateFormView(Model model) { model.addAttribute("title", "Create Event Form"); model.addAttribute(new Events()); // 传递所有枚举值到视图 model.addAttribute("types", TypeOfEvents.values()); return "events/create"; }
4. 原Thymeleaf模板代码
<label>Type of Event</label> <div class="dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropDownMenu2" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Select</button> <div class="dropdown-menu" aria-labelledby="dropDownMenu2" th:field="${events.typeOfEvents}"> <button class="dropdown-item" type="button" th:each="type :${types}" th:value="${type}" th:text="${type.displayEventType}"> </button> </div> </div>
问题分析
- Bootstrap下拉组件未初始化:Bootstrap的下拉菜单依赖jQuery、Popper.js和Bootstrap JS文件,若未正确引入这些资源,点击下拉按钮后菜单无法展开,导致内容虽已生成但不可见。
- 表单绑定逻辑错误:
th:field绑定到div.dropdown-menu无效,因为div不是表单控件,无法将选中值绑定到events.typeOfEvents;同时用button作为下拉选项,默认不会触发表单值的更新。
解决方案
方案1:改用Bootstrap自定义样式的select控件(表单场景更简单)
用select配合Bootstrap的form-select类,既满足表单绑定需求,又能实现下拉选择样式:
<label for="eventType" class="form-label">Type of Event</label> <select class="form-select" th:field="${events.typeOfEvents}" id="eventType"> <option value="">Select</option> <option th:each="type : ${types}" th:value="${type}" th:text="${type.displayEventType}"> </option> </select>
方案2:修复原下拉菜单的问题(保留button下拉样式)
若坚持使用Bootstrap的dropdown组件,需做以下调整:
- 在页面
</body>前引入必要的JS文件:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script>
- 修改模板,添加隐藏输入框绑定表单字段,同时给下拉按钮添加点击事件更新选中值:
<label>Type of Event</label> <div class="dropdown"> <!-- 下拉触发按钮,显示当前选中的类型 --> <button class="btn btn-secondary dropdown-toggle" type="button" id="dropDownMenu2" data-bs-toggle="dropdown" aria-expanded="false"> <span id="selectedType">Select</span> </button> <!-- 隐藏输入框,用于绑定表单字段 --> <input type="hidden" th:field="${events.typeOfEvents}" id="eventTypeInput"> <div class="dropdown-menu" aria-labelledby="dropDownMenu2"> <button class="dropdown-item" type="button" th:each="type :${types}" th:data-value="${type}" th:text="${type.displayEventType}" onclick="selectEventType(this)"> </button> </div> </div> <script> function selectEventType(button) { const value = button.getAttribute('data-value'); const text = button.textContent; // 更新隐藏输入框的值 document.getElementById('eventTypeInput').value = value; // 更新下拉按钮的显示文本 document.getElementById('selectedType').textContent = text; } </script>
注:若使用Bootstrap 4,需将data-bs-toggle改为data-toggle,并对应调整JS文件版本。
内容的提问来源于stack exchange,提问作者Johndavid Cabal
相关产品推荐
相关产品推荐

