JQuery, как перебирать несколько файлов JSON для создания викторины

Я застрял, и мне нужна ваша помощь, пожалуйста. Я создаю интерфейс для викторины. По какой-то причине серверная часть предоставляет 3 файла json. JSON1 дает мне категорию и заголовок (https://api.myjson.com/bins/nilct ). JSON2 дает мне вопросы (https://api.myjson.com/bins/1178p1). Возможные ответы JSON3 (https://api.myjson.com/bins/qhft1).

Мне нужно перебрать JSON1 и написать категории и заголовки. Прокрутите JSON2 и напишите вопрос для этого заголовка. Прокрутите JSON3 и напишите возможные ответы на каждый вопрос.

Это мой html-файл:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>quiz</title>
</head>
<body>
    <div id="bigMain" class="hide">

    </div>  

    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script src="js/refactor3.js"></script>
</body>
</html>

Это мой файл JavaScript:

var request1 = $.ajax({
    url: 'https://api.myjson.com/bins/nilct',
    dataType: 'json',
    type: 'get',
    cache: false,
    success: function(data) {

        var key, jsoncount = 0;
        for(key in data) {
            if(data.hasOwnProperty(key)) {
                jsoncount++;
            }
        }
        $(data).each(function(index, value){
            var categoryId = value.id;
            var catCategory = value.category;
            var catHeader = value.header;
            var catOrderNum = value.question;

            var getSectionPlace = document.getElementById('bigMain');
            var maturidadeSection = 
                '<section id="' + categoryId + '">\
                    <div class="section-top">\
                        <p class="title optionsTitle '+ catCategory +' titleFor_'+ categoryId + '">\
                        ' + catCategory + '\
                        </p>\
                        <hr class="hideOnMobile">\
                        <h1 class="top-title">'+ catHeader +'</h1>\
                    </div>\
                    <div class="section-bottom">\
                    And this is bottom div\
                    </div>\
                </section>';


        function makeSections(){
            $( maturidadeSection ).appendTo( getSectionPlace );
        }
        makeSections();

        });
    }
}),

request2 = $.ajax({
        url: 'https://api.myjson.com/bins/1178p1',
        dataType: 'json',
        type: 'get',
        cache: false,
        success: function(data) {
            //console.table(data);
            var key, jsoncount = 0;
            for(key in data) {
                if(data.hasOwnProperty(key)) {
                jsoncount++;

                }
            }

            $(data).each(function(index, value){
                var questionId = value.id;
                var questionText = value.question;
                var questionOrderNum = value.orderNum;
                var questionType = value.type;
                var questionBelongsTo = value.category_id;

    /**
     * Get the place to put content inside sections and place it
     */
            var getQuestionPlace = document.getElementsByClassName('section-bottom');
            var questionToPlace = '<div class="question question' + questionBelongsTo + '">\
                                        <p class="questionP questionId_'+questionId+'">\
                                            ' + questionText + 
                                        '</p>\
                                        <ul id="questionId-'+ questionId +'" class="answerContainer">\
                                            <li>TESTS</li>\
                                        </ul>\
                                   </div>'

                                   function makeQuestions(){
                                       $( questionToPlace ).appendTo( getQuestionPlace );
                                    }
                                    makeQuestions();

            });

        }    
    }),
request3 = $.ajax({
    url: 'https://api.myjson.com/bins/qhft1',
    dataType: 'json',
    type: 'get',
    cache: false,
    success: function(data) {
        var key, jsoncount = 0;
        for(key in data) {
            if(data.hasOwnProperty(key)) {
            jsoncount++;
            }
        }

        $(data).each(function(index, value){
            var answerId = value.id;
            var answerText = value.answer;
            var answerOrderNum = value.orderNum;

    /**
     * Get the place to put content inside sections and place it
     */
            var getAnswerPlace = document.getElementsByClassName('answerContainer');
            var answerToPlace = '<li><input type="radio" name="'+ answerOrderNum +'" value="'+ answerText +'">\
                                    '+ answerText +'\
                                </li>'

                                   function makeAnswers(){
                                       $( answerToPlace ).appendTo( getAnswerPlace );
                                    }
                                    makeAnswers();

            });
        }    
    });

Но это не работает, так как я не могу контролировать, что происходит в каком цикле, и у меня большой беспорядок.

Может ли кто-нибудь помочь мне со способом сделать это? И получить все данные из одного JSON невозможно.

Заранее спасибо!


person fropt    schedule 29.09.2019    source источник
comment
это не работает - звучит как проблема... можете ли вы описать, что делает код и чем он отличается от того, что вы от него ожидаете. Также проверьте консоль инструментов разработчика браузера на наличие ошибок — есть ли они?   -  person Jaromanda X    schedule 29.09.2019
comment
кажется, по крайней мере, отсутствует }}), непосредственно перед request2 = $.ajax({   -  person Jaromanda X    schedule 29.09.2019
comment
Спасибо. Это была моя ошибка при размещении и очистке кода, чтобы сделать его короче. Проблема в том, что он создает что-то вроде: Заголовок A вопросA ответ A1 ответ A2 ответ B1 ... вопрос B ответ A1 ответ A2 ответ B1 ... вопрос B   -  person fropt    schedule 29.09.2019


Ответы (3)


Во-первых, fropt, добро пожаловать в StackOverflow :)

de um tuga para outro, Bem Vindo!

во-вторых... ваш вопрос.

Что ж, я вижу беспорядок в этом коде, поэтому я бы предложил вместо того, чтобы просто помочь исправить это... другой путь, чтобы вы могли иметь полный контроль над тем, что происходит, и упростить улучшение и исправление любых ошибок. код:

Поскольку вы повторяете свой код и используете небольшие фрагменты HTML, я настоятельно рекомендую очень небольшой инструмент, например JsRender от одного из наших членов (вы можете использовать Handlebars или Mustache, но они немного больше и со слишком большим функционалом мы даже не будем использовать)

для таких я бы сделал:

  • иметь массив со всеми вашими URL-адресами
  • пройти их все
  • чтобы было легче манипулировать, добавьте дочерние данные к родительскому объекту
  • сохранить все данные в глобальный объект
  • визуализировать ваш шаблон с собранными данными

предостережение:

если вы можете использовать промисы, вы можете воспользоваться преимуществом запуска всех 3 запросов одновременно и подождать, пока все не будет выполнено, и продолжить... например:


  var settings = [
    // categories
    'https://api.myjson.com/bins/nilct',
    // questions
    'https://api.myjson.com/bins/1178p1',
    // answers
    'https://api.myjson.com/bins/qhft1',
  ];


  Promise.all([
    getData(settings[0]),
    getData(settings[1]),
    getData(settings[2])
  ]).then(function(allData) {
    var categories = allData[0],
        questions = allData[1],
        answers = allData[2];

    // append all categoties to our global object
    formData = categories;
    // append all questions to each category
    formData.forEach(function(x) {
      x.questions = questions;
      // append all answers to each question
      x.questions.forEach(function(y) {
        y.answers = answers;
      });
    });

  processData(formData, '#tmplForm', '#main-quiz');

Если вы не можете (например, IE11 не может работать с промисами), я написал почти такой же код.

Вот мое мнение, если бы у меня возникла проблема с кодом...

$(function() {

  var formData = [];
  var settings = [
    // categories
    'https://api.myjson.com/bins/nilct',
    // questions
    'https://api.myjson.com/bins/1178p1',
    // answers
    'https://api.myjson.com/bins/qhft1',
  ];
  
  
  // if Promises are available, use this code
  /*
  Promise.all([
    getData(settings[0]),
    getData(settings[1]),
    getData(settings[2])
  ]).then(function(allData) {
    var categories = allData[0],
        questions = allData[1],
        answers = allData[2];
    
    formData = categories;
      // now that we have all questions, append them to categories
      formData.forEach(function(x) {
        x.questions = questions;
        // now that we have all answers, append them to questions
        x.questions.forEach(function(y) {
          y.answers = answers;
        });
      });
      
    processData(formData, '#tmplForm', '#main-quiz');
    $('.btn-submit').show();
  }); */
  
  // if you can't use Promises, use the code below
  $.getJSON(settings[0], function(data) { 
    formData = data;
    
    $.getJSON(settings[1], function(data) {
      
      // now that we have all questions, append them to categories
      formData.forEach(function(x) {
        x.questions = data;
      });
      
      $.getJSON(settings[2], function(data) {
        
        // now that we have all answers, append them to questions
        formData.forEach(function(x) {
          x.questions.forEach(function(y) {
            y.answers = data;
          });
        });
        
        // console.log(JSON.stringify(formData, null, 4))
        processData(formData, '#tmplForm', '#main-quiz');
        $('.btn-submit').show();
      });
    });
  });
  /* */

  // submit button event
  $('.btn-submit').on('click', submitData);
});

function processData(data, scriptTmpl, appendTo) {
  // get the template
  var template = $.templates(scriptTmpl);
  // convert to HTML
  var htmlOutput = template.render(data);
  // append to html element
  $(appendTo).append(htmlOutput);
}

function submitData(evt) {
  var answersData = [];
  var questions = $('#main-quiz .question');
  console.log('FOUND ' + questions.length + ' questions');
  
  questions.each(function (i, q) {
    var question = $(q);
    var answer = $(q).find('input[type="radio"]:checked'); // selected answer
    answersData.push({
      id: answer.data('id') || '', // the answer id
      answer: answer.val() || '' // the actual answer
    });
  });

  // let's see those answers
  console.log(JSON.stringify(answersData, null, 4));
}

// it's only used on the Promises code
function getData(url) {
  return new Promise(function(resolve, reject) {
    $.getJSON(url, function(data) { resolve(data); });
  });
}
.btn-submit { display: none; }
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/1.0.5/jsrender.min.js"></script>

  <div id="main-quiz"></div>
  <button class="btn-submit">Submit answers</button>
  
  <script id="tmplForm" type="text/x-jsrender">
    <section id="section-{{:id}}" data-id="{{:id}}">
      
      <div class="section-top">
        <hr class="hideOnMobile">
        <h1 class="top-title">#{{:id}} {{:category}}</h1>
        <p class="title optionsTitle {{:category}} titleFor_{{:id}}">{{:header}}</p>
      </div>
      
      <div class="section-bottom">
        And this is bottom div
        
        {{for questions}}
          <div data-id="{{:id}}" class="question question{{:category_id}}" data-parentid="{{:#parent.data.id}}">
            <p class="questionP questionId_{{:id}}">{{:question}}</p>
            
            <ul id="questionId-{{:id}}" class="answerContainer">
              
              {{for answers}}
                <li data-id="{{:id}}" data-parentid="{{:#parent.parent.data.id}}">
                  <label for="answer_{{:#parent.parent.parent.parent.data.id}}_{{:#parent.parent.data.id}}_{{:id}}">
                    <input data-id="{{:#parent.parent.parent.parent.data.id}}_{{:#parent.parent.data.id}}_{{:id}}" type="radio" 
                    name="answer_{{:#parent.parent.parent.parent.data.id}}_{{:#parent.parent.data.id}}" 
                    id="answer_{{:#parent.parent.parent.parent.data.id}}_{{:#parent.parent.data.id}}_{{:id}}" 
                    value="{{:answer}}" />
                    {{:answer}}
                  </label>
                </li>
              {{/for}}
              
            </ul>
          </div>
        {{/for}}
        
      </div>
    </section>
  </script>

Есть много вещей, которые нужно учитывать, но отделение HTML от вашего JavaScript — лучшая идея, так как вы можете сосредоточиться на том, что делает одно и другое, и никогда не беспокоиться, если вам где-то не хватает закрывающего тега или запятой ... делает это еще проще тоже следить :)

единственное, что вы можете не понять поначалу, — это доступ к родительским данным, но вы можете видеть, что это хорошо объяснено в документация.

P.S. Я также немного отредактировал исходный HTML-код, чтобы его было легче увидеть... возможно, это не тот результат, который вам нужен, но это только для того, чтобы лучше продемонстрировать сценарий с дырой.

П.П.С. вот полный пример на JSBIN

person balexandre    schedule 29.09.2019
comment
ахах Обригадо! Правило Туги :) Большое спасибо за качество и глубину детализации вашего решения. Это действительно меняет игру для меня. Ты жжешь!! :) - person fropt; 30.09.2019

Кажется, есть проблема с тем, когда импортировать файлы. Проблема решается загрузкой файлов сразу и обработкой json сразу.

$.ajax({
  url: 'https://api.myjson.com/bins/nilct',
  dataType: 'json',
  type: 'get',
  cache: false,
  success: function(title) {
    $.ajax({
      url: 'https://api.myjson.com/bins/1178p1',
      dataType: 'json',
      type: 'get',
      cache: false,
      success: function(qustion) {
        $.ajax({
          url: 'https://api.myjson.com/bins/qhft1',
          dataType: 'json',
          type: 'get',
          cache: false,
          success: function(answer) {
            randerHtml(title, qustion, answer);
          }
        });
      }
    });
  }
});

function randerHtml(title, qustion, answer) {
  console.log(title, qustion, answer);
}
person hagon    schedule 29.09.2019
comment
Спасибо, что заметили это, но это была ошибка, которую я допустил, размещая код здесь. Кажется, мыли больше, чем следовало. Я отредактирую вопрос, но настоящая проблема остается. - person fropt; 29.09.2019
comment
Что именно ты пытаешься сделать? Видите ли вы «запрос2», «запрос3» иногда при каждом обновлении? - person hagon; 29.09.2019
comment
Благодарю вас! Я попробую. Имеет смысл, просто прочитав это. Я проголосую сразу после! Еще раз спасибо :) - person fropt; 29.09.2019

Проверь это

$.ajax({
  url: 'https://api.myjson.com/bins/nilct',
  dataType: 'json',
  type: 'get',
  cache: false,
  success: function(cats) {
    drawCats(cats);
    $.ajax({
      url: 'https://api.myjson.com/bins/1178p1',
      dataType: 'json',
      type: 'get',
      cache: false,
      success: function(qustions) {
        drawQuestions(qustions);
        $.ajax({
          url: 'https://api.myjson.com/bins/qhft1',
          dataType: 'json',
          type: 'get',
          cache: false,
          success: function(answers) {
            drawAnswers(answers);
          }
        });
      }
    });
  }
});


function drawCats(cats){
    $(cats).each(function(index, value){
        var categoryId = value.id;
        var catCategory = value.category;
        var catHeader = value.header;
        var catOrderNum = value.question;

        var maturidadeSection = 
            '<section id="cat_' + categoryId + '" class="cats" data-id="' + categoryId + '">\
                <div class="section-top">\
                    <p class="title optionsTitle '+ catCategory +' titleFor_'+ categoryId + '">\
                    ' + catCategory + '\
                    </p>\
                    <hr class="hideOnMobile">\
                    <h1 class="top-title">'+ catHeader +'</h1>\
                </div>\
                <div class="section-bottom">\
                And this is bottom div\
                </div>\
            </section>';
        $("#bigMain").append(maturidadeSection);
    });
}

function drawQuestions(qustions){

    $(qustions).each(function(index, value){
        var questionId = value.id;
        var questionText = value.question;
        var questionOrderNum = value.orderNum;
        var questionType = value.type;
        var questionBelongsTo = value.category_id;

        $(".cats").each(function(){
        if($(this).data("id") == questionBelongsTo) {
            var questionToPlace = '<div class="question question' + questionBelongsTo + '">\
                            <p class="questionP questionId_'+questionId+'">\
                                        ' + questionText + 
                                    '</p>\
                                    <ul id="questionId-'+ questionId +'" class="answerContainer">\
                                    </ul>\
                               </div>';
                    $( questionToPlace ).appendTo($(".section-bottom",this));

            }
         });

    });
}

function drawAnswers(answers){
    console.log(answers)
}
person Ahmed El-sayed    schedule 29.09.2019
comment
Привет, Ахмед Эль-Саид, спасибо! Я попробую :) - person fropt; 29.09.2019