Не получается добавить весь список из объектов в json ответе , добавляется только самый первый объект

Не получается добавить весь список из объектов в json ответе , добавляется только самый первый объект , делаю что то типа конструктора анкеты с любым количеством вопросов и в них ответами, теста , и хочу отправить в контроллер JSON объект для дальнейшей обработки , отправляется один объект Survey , состоящий из названия и списка объектов Question , тот в свою очередь тоже состоит из названия и списка из объектов Ansver , а этот состоит из названия и булевого значения. Самое главное, что передаются все объекты Question в списке, но у самого Question в списке ответов добавляется только самый первый ответ , вот пример JSON

{"name":"опрос","questions":
[{"title":"вопрос1","answers":[{"title":"ответ1","isCorrect":false}]},
{"title":"вопрос2","answers":[{"title":"ответ1","isCorrect":true}]}]}

страница

вот html


    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <meta name="view" content="width=device-width, initial-scale=1.0">
        <title>Вопросы и ответы</title>
        <link rel="stylesheet" type="text/css" href="/static/new.css">
    </head>
    <body>
    <h1>Вопросы и ответы</h1>
    <form th:action="@{/survey}" method="post" enctype="application/json">
        <div class="button-container">
            <button type="button" class="add-question-button">Добавить вопрос</button>
            <input type="submit" class="save-button" value="Сохранить опрос">
        </div>
    
        <div class="survey-name-container">
            <label for="survey-name">Название опроса:</label>
            <input type="text" name="survey-name" id="survey-name">
        </div>
    
        <div class="question-container hidden">
            <label for="question-title">Текст вопроса:</label>
            <input type="text" name="question-title" id="question-title">
    
            <div class="answer-container">
                <label for="answer-title">Текст ответа:</label>
                <input type="text" name="answer-title" id="answer-title">
    
                <label for="is-correct">Является ли правильным:</label>
                <input type="checkbox" name="is-correct" id="is-correct">
    
                <input type="hidden" name="is-correct" value="">
                <button type="button" class="add-answer-button">Добавить ответ</button>
            </div>
        </div>
    
        <div class="dynamic-container">
            <!-- Динамический контент -->
        </div>
    </form>
    
    <script>
        const addQuestionButton = document.querySelector('.add-question-button');
        const questionContainers = document.querySelectorAll('.question-container');
        const dynamicContainer = document.querySelector('.dynamic-container');
    
        addQuestionButton.addEventListener('click', () => {
            const lastQuestionContainer = questionContainers[questionContainers.length - 1];
    
            // Клонируем последний контейнер с вопросом
            const newQuestionContainer = lastQuestionContainer.cloneNode(true);
    
            // Очищаем поля в новых вопросах
            const questionTitleInput = newQuestionContainer.querySelector('#question-title');
            questionTitleInput.value = '';
    
            // Очищаем поля в новых ответах
            const answerContainer = newQuestionContainer.querySelector('.answer-container');
            const answerTitle = answerContainer.querySelectorAll('#answer-title');
            answerTitle.forEach(input => {
                input.value = '';
            });
    
            // Добавляем обработку событий для кнопки добавления ответа
            const addAnswerButton = answerContainer.querySelector('.add-answer-button');
            addAnswerButton.addEventListener('click', () => {
                const newAnswer = document.createElement('div');
                newAnswer.innerHTML = `
                    <label for="answer-title">Текст ответа:</label>
                    <input type="text" name="answer-title" id="answer-title">
    
                    <label for="is-correct">Является ли правильным:</label>
                    <input type="checkbox" name="is-correct" id="is-correct">
                `;
    
                answerContainer.appendChild(newAnswer);
            });
    
            // Добавляем новый вопрос в динамический контент
            dynamicContainer.appendChild(newQuestionContainer);
        });
    
        questionContainers.forEach(container => {
            const addAnswerButton = container.querySelector('.add-answer-button');
    
            addAnswerButton.addEventListener('click', () => {
                const newAnswer = document.createElement('div');
                newAnswer.innerHTML = `
                    <label for="answer-title">Текст ответа:</label>
                    <input type="text" name="answer-title" id="answer-title">
    
                    <label for="is-correct">Является ли правильным:</label>
                    <input type="checkbox" name="is-correct" id="is-correct">
                `;
    
                container.querySelector('.answer-container').appendChild(newAnswer);
            });
        });
    
        // Создаем объект опроса
        const survey = {
            name: '',
            questions: []
        };
    
        // Создаем объект вопроса
        const question = {
            title: '',
            answers: []
        };
    
        // Создаем объект ответа
        const answer = {
            title: '',
            isCorrect: false
        };
    
        // Добавляем обработку события "submit" для формы
        const form = document.querySelector('form');
        form.addEventListener('submit', (event) => {
            event.preventDefault();
    
            // Получаем название опроса
            const surveyName = document.querySelector('#survey-name').value;
    
            // Устанавливаем название опроса
            survey.name = surveyName;
    
            // Получаем все контейнеры с вопросами
            const questionContainers = document.querySelectorAll('.question-container');
    
            // Итерируем по контейнерам с вопросами
            questionContainers.forEach(container => {
                // Получаем заголовок вопроса
                const questionTitle = container.querySelector('#question-title').value;
    
                // Создаем новый объект вопроса
                const newQuestion = {
                    title: questionTitle,
                    answers: []
                };
    
                // Получаем все контейнеры с ответами
                const answerContainers = container.querySelectorAll('.answer-container');
    
                // Итерируем по контейнерам с ответами
                answerContainers.forEach(answerContainer => {
                    // Получаем заголовок ответа
                    const answerTitle = answerContainer.querySelector('#answer-title').value;
    
                    // Получаем флаг правильности ответа
                    const isCorrect = answerContainer.querySelector('#is-correct').checked;
    
                    // Создаем новый объект ответа
                    const newAnswer = {
                        title: answerTitle,
                        isCorrect: isCorrect
                    };
    
                    // Добавляем новый объект ответа в массив ответов
                    newQuestion.answers.push(newAnswer);
                });
    
                // Добавляем новый объект вопроса в массив вопросов
                survey.questions.push(newQuestion);
            });
    
            // Отправляем данные на сервер
            const data = JSON.stringify(survey);
            const xhr = new XMLHttpRequest();
    
            console.log(JSON.stringify(data, null, 2));
            xhr.open('POST', '/survey', true);
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(data);
        });
    </script>
    </body>
    </html>

не понимаю что не так, со списком из Question работает, а Ansver не собирается , а добавляется только самый первый элемент...


Ответы (1 шт):

Автор решения: MrFylypenko

У Вас проблема с неправильной вложенностью элементов в div class="answer-container", первоначально добавлены элементы label, input, но когда добавляется следующий ответ, то вложенность становится неправильной. Это можно увидеть в консоли браузера на вкладке Elements (на скриншоте она есть), когда доберетесь до нужного элемента. Также неправильный поиск ответов через querySelectorAll.

<div class="answer-container"> 
    <label .../> <input...> 
    <div name="новый ответ"  > <label .../> <input...>   </div> 
</div>

Исправил вложенность для первого ответа, исправил получение всех ответов const answerContainers = container.querySelector('.answer-container').children и его перебор в цикле. Другие ошибки не исправлял.

const addQuestionButton = document.querySelector('.add-question-button');
const questionContainers = document.querySelectorAll('.question-container');
const dynamicContainer = document.querySelector('.dynamic-container');

addQuestionButton.addEventListener('click', () => {
  const lastQuestionContainer = questionContainers[questionContainers.length - 1];

  // Клонируем последний контейнер с вопросом
  const newQuestionContainer = lastQuestionContainer.cloneNode(true);

  // Очищаем поля в новых вопросах
  const questionTitleInput = newQuestionContainer.querySelector('#question-title');
  questionTitleInput.value = '';

  // Очищаем поля в новых ответах
  const answerContainer = newQuestionContainer.querySelector('.answer-container');
  const answerTitle = answerContainer.querySelectorAll('#answer-title');
  answerTitle.forEach(input => {
    input.value = '';
  });

  // Добавляем обработку событий для кнопки добавления ответа
  const addAnswerButton = answerContainer.querySelector('.add-answer-button');
  addAnswerButton.addEventListener('click', () => {
    const newAnswer = document.createElement('div');
    newAnswer.innerHTML = `
                    <label for="answer-title">Текст ответа:</label>
                    <input type="text" name="answer-title" id="answer-title">
    
                    <label for="is-correct">Является ли правильным:</label>
                    <input type="checkbox" name="is-correct" id="is-correct">
                `;

    answerContainer.appendChild(newAnswer);
  });

  // Добавляем новый вопрос в динамический контент
  dynamicContainer.appendChild(newQuestionContainer);
});

questionContainers.forEach(container => {
  const addAnswerButton = container.querySelector('.add-answer-button');

  addAnswerButton.addEventListener('click', () => {
    const newAnswer = document.createElement('div');
    newAnswer.innerHTML = `
                    <label for="answer-title">Текст ответа:</label>
                    <input type="text" name="answer-title" id="answer-title">
    
                    <label for="is-correct">Является ли правильным:</label>
                    <input type="checkbox" name="is-correct" id="is-correct">
                `;

    container.querySelector('.answer-container').appendChild(newAnswer);
  });
});

// Создаем объект опроса
const survey = {
  name: '',
  questions: []
};

// Создаем объект вопроса
const question = {
  title: '',
  answers: []
};

// Создаем объект ответа
const answer = {
  title: '',
  isCorrect: false
};

// Добавляем обработку события "submit" для формы
const form = document.querySelector('form');
form.addEventListener('submit', (event) => {
  event.preventDefault();

  // Получаем название опроса
  const surveyName = document.querySelector('#survey-name').value;

  // Устанавливаем название опроса
  survey.name = surveyName;

  // Получаем все контейнеры с вопросами
  const questionContainers = document.querySelectorAll('.question-container');

  // Итерируем по контейнерам с вопросами
  questionContainers.forEach(container => {
    // Получаем заголовок вопроса
    const questionTitle = container.querySelector('#question-title').value;

    // Создаем новый объект вопроса
    const newQuestion = {
      title: questionTitle,
      answers: []
    };

    // Получаем все контейнеры с ответами
    const answerContainers = container.querySelector('.answer-container').children;

    // Итерируем по контейнерам с ответами
    for (var i = 0; i < answerContainers.length; i++) {

      var answerContainer = answerContainers[i];

      // Получаем заголовок ответа
      const answerTitle = answerContainer.querySelector('#answer-title').value;

      // Получаем флаг правильности ответа
      const isCorrect = answerContainer.querySelector('#is-correct').checked;

      // Создаем новый объект ответа
      const newAnswer = {
        title: answerTitle,
        isCorrect: isCorrect
      };

      // Добавляем новый объект ответа в массив ответов
      newQuestion.answers.push(newAnswer);
    };

    // Добавляем новый объект вопроса в массив вопросов
    survey.questions.push(newQuestion);
  });

  // Отправляем данные на сервер
  const data = JSON.stringify(survey);
  const xhr = new XMLHttpRequest();

  console.log(JSON.stringify(data, null, 2));
  xhr.open('POST', '/survey', true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.send(data);
});
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
  <meta charset="UTF-8">
  <meta name="view" content="width=device-width, initial-scale=1.0">
  <title>Вопросы и ответы</title>
  <link rel="stylesheet" type="text/css" href="/static/new.css">
</head>

<body>
  <h1>Вопросы и ответы</h1>
  <form th:action="@{/survey}" method="post" enctype="application/json">
    <div class="button-container">
      <button type="button" class="add-question-button">Добавить вопрос</button>
      <input type="submit" class="save-button" value="Сохранить опрос">
    </div>

    <div class="survey-name-container">
      <label for="survey-name">Название опроса:</label>
      <input type="text" name="survey-name" id="survey-name">
    </div>

    <div class="question-container hidden">
      <label for="question-title">Текст вопроса:</label>
      <input type="text" name="question-title" id="question-title">

      <div class="answer-container">
        <div>
          <label for="answer-title">Текст ответа:</label>
          <input type="text" name="answer-title" id="answer-title">

          <label for="is-correct">Является ли правильным:</label>
          <input type="checkbox" name="is-correct" id="is-correct">

          <input type="hidden" name="is-correct" value="">
          <button type="button" class="add-answer-button">Добавить ответ</button>
        </div>
      </div>
    </div>

    <div class="dynamic-container">
      <!-- Динамический контент -->
    </div>
  </form>
</body>

</html>

→ Ссылка