Spring Boot+Thymeleaf投票系统新增选项归属异常问题
问题根源
问题出在前端JavaScript的闭包陷阱:当新增第二个问题时,给「Add Option」按钮绑定点击事件时,直接引用了外部的questionIndex变量。由于questionIndex后续会被递增,当用户实际点击第二个问题的「Add Option」按钮时,questionIndex已经变成了2(而非预期的1),导致生成的表单字段名是questions[2].options[...].description,而非questions[1].options[...].description。
后端Spring MVC在绑定表单数据时,会自动创建索引为2的空QuestionData对象,并将新增选项绑定到这个空问题上,最终出现你看到的异常结果。
修复方案
在addQuestionBlock函数中,绑定「Add Option」按钮的点击事件时,需要捕获当前的questionIndex值,避免闭包引用后续被修改的外部变量。
修改后的JavaScript代码片段
将addQuestionBlock函数中的事件绑定部分替换为:
// 捕获当前的questionIndex值,避免闭包陷阱 const currentQuestionIndex = questionIndex; newQuestionBlock.querySelector('.add-option-btn').addEventListener('click', function () { addOption(newQuestionBlock.querySelector('.optionsContainer'), currentQuestionIndex); });
完整的addQuestionBlock函数修改后如下:
// Function to add a new question block function addQuestionBlock() { const questionsContainer = document.getElementById('questionsContainer'); const newQuestionBlock = document.createElement('div'); newQuestionBlock.className = 'question-block form-group'; newQuestionBlock.setAttribute('data-question-index', questionIndex); // Set data attribute for easier access newQuestionBlock.innerHTML = ` <label>Question:</label> <input type="text" name="questions[${questionIndex}].text" class="form-control mb-2" placeholder="Question Text" required> <div class="optionsContainer"> <div class="form-group option-block"> <input type="text" name="questions[${questionIndex}].options[0].description" class="form-control mb-2" placeholder="Option 1" required> </div> <div class="form-group option-block"> <input type="text" name="questions[${questionIndex}].options[1].description" class="form-control mb-2" placeholder="Option 2" required> </div> </div> <button type="button" class="btn btn-secondary add-option-btn mb-2">Add Option</button> `; questionsContainer.appendChild(newQuestionBlock); // Initialize the option index for this question optionIndices[questionIndex] = 2; // 捕获当前的questionIndex值,避免闭包陷阱 const currentQuestionIndex = questionIndex; // Add event listener for adding options in this question block newQuestionBlock.querySelector('.add-option-btn').addEventListener('click', function () { addOption(newQuestionBlock.querySelector('.optionsContainer'), currentQuestionIndex); }); questionIndex++; // Increment the question index }
验证效果
修改后,给第二个问题添加选项时,生成的表单字段名将正确为questions[1].options[2].description、questions[1].options[3].description等,后端会将这些选项正确绑定到第二个问题上,不会再生成空的第三个问题。
内容的提问来源于stack exchange,提问作者meow
相关产品推荐
相关产品推荐

