You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:23:11