1

Might be a simple question for some, but im currently stuck here.

What i'm trying to create is a quiz, that grabs the questions, answers, solutions and the type of question from a JSON.
So far, it works and i get an array with the answers selected and removing the answers that are unselected. But the array gets filled with the id, but i actually want it's answerList index.

   {
    "quid":1,
    "question": "question 1",
    "answerList":["answer 1_1","answer 1_2"],
    "solution":[1],
    "type":"checkbox"
   }

This is what my JSON looks like. When running the code below, and checking both boxes, i get an array as ["answer1_1", "answer1_2"]. But i need an array like [0, 1] because i later on want to compare it to the solution, to see if the selection was correct or not. Also, since there are mulitple checkbox questions (i removed everything else since it's irelevant here), it gets all pushed into the same array. Ideally i'd get arr1=[0, 1], if both were selected in this case and arr=[0, 1, 2] for the next.
Maybe i've been sitting here for too long to not see the obvious, simple answer to my question.

Anyway, here is a code snippet.

//Parse JSON
let quizDyn = JSON.parse(`[
    {
        "quid":1,
        "question": "question 1",
        "answerList":["answer 1_1","answer 1_2"],
        "solution":[1],
        "type":"checkbox"

    }, {
        "quid":2,
        "question": "question 2",
        "answerList":["answer 2_1","answer 2_2","answer 2_3"],
        "solution":[0,1,2],
        "type":"checkbox"
    }, {
        "quid":3,
        "question": "question 3",
        "answerList":["answer 3_1","answer 3_2","answer 3_3","answer 3_4"],
        "solution":[0],
        "type":"checkbox"
    }
]`)

// just creating a div here
var spalteQuiz = document.createElement("div")
spalteQuiz.setAttribute("class", "spalteQuiz")
document.body.append(spalteQuiz)


for (var i = 0; i < quizDyn.length; i++) {

  var neuesQuiz = document.createElement("div")
  neuesQuiz.setAttribute("class", "quiz")
  var aktuellesQuiz = document.getElementById("pOut")

  neueFrage = document.createElement("p")
  neueFrage.setAttribute("class", "frage")
  neueFrage.setAttribute("id", "frage " + (i + 1) + " frage")
  neueFrage.setAttribute("name", "frage " + (i + 1) + " frage")
  neueFrage.textContent = quizDyn[i].question
  var aktuelleFrage = document.getElementById("divOut")

  spalteQuiz.append(neuesQuiz)
  neuesQuiz.append(neueFrage)

  var frageTyp = quizDyn[i].type
  var anzahlAntworten = quizDyn[i].answerList.length
  var quidi = quizDyn[i].quid
  var quid = quizDyn.quid
  var entferneLeerzeichen = str => str.replace(/[\s,.]/g, '')


  // variable used for my array
  var loesung = []

  // function that's used for questions that are to be answered with checkboxes
  function istCheckbox() {

    //creating the <form>'s 
    var form = document.createElement("form")
    form.setAttribute("name", "frage" + quidi + "form")
    neuesQuiz.append(form)

    // creating the <input>'s
    for (let i = 0; i < anzahlAntworten; i++) {

      checkbox = document.createElement("input")
      checkbox.setAttribute("type", "checkbox")
      checkbox.setAttribute("name", "frage" + quidi + "checkbox")
      checkbox.setAttribute("id", entferneLeerzeichen(quizDyn[quidi - 1].answerList[i]))


      // creating the <label>'s
      var label = document.createElement("label")
      label.textContent = quizDyn[quidi - 1].answerList[i]
      label.setAttribute("for", entferneLeerzeichen(quizDyn[quidi - 1].answerList[i]))

      // here i check if the checkbox is checked
      checkbox.addEventListener('change', function() {

        // if it's checked, push the checkboxes id to the array
        if (this.checked) {
          loesung.push(this.id)
        } else {
          // when unchecking, find the index of the unchecked checkbox'S id
          index = loesung.indexOf(this.id)
          // splice 1 object at the position of index
          loesung.splice(index, 1)
        }
        // console log the array
        console.log(loesung)
      })

      // appending it all
      var zeilenUmbruch = document.createElement("br")
      form.append(checkbox)
      form.append(label)
      form.append(zeilenUmbruch)
    }
  }

  //there is more usually, because irelevant
  function istTyp() {
    istCheckbox()
  }

  istTyp()
}

4
  • when creating the checkbox (I'd use radio instead for obvious reasons) - add a value to it - then use the value rather than the id when pushing to the array - obviously another issue in your code is that the questions can be answered in any order - which means the array will not be in the right order Commented Jun 20, 2021 at 0:51
  • But with radio i could only check a single answer for each, while some have more than one answer to check. Commented Jun 20, 2021 at 10:11
  • Interesting, so, how would you know if [0,1] is two answers for the first question or 1 answer for the 1st and 2nd? Seems like what you do now makes more sense Commented Jun 20, 2021 at 10:13
  • My idea was to get for example [0,1,2] when all three options are checked at the second answer and compare that to the solutions for that question, which is also [0,1,2] if it's the same, question is answered correctly, if not, it's incorrect. Haven't done that before, but that was the idea i came up with Commented Jun 20, 2021 at 10:27

2 Answers 2

1

Based on your design, i commented what i did to your event listener.

// Parse JSON
const quizDyn = JSON.parse(`[
  {
      "quid":1,
      "question": "question 1",
      "answerList":["answer 1_1","answer 1_2"],
      "solution":[1],
      "type":"checkbox"

  }, {
      "quid":2,
      "question": "question 2",
      "answerList":["answer 2_1","answer 2_2","answer 2_3"],
      "solution":[0,1,2],
      "type":"checkbox"
  }, {
      "quid":3,
      "question": "question 3",
      "answerList":["answer 3_1","answer 3_2","answer 3_3","answer 3_4"],
      "solution":[0],
      "type":"checkbox"
  }
]`)

// just creating a div here
const spalteQuiz = document.createElement('div')
spalteQuiz.setAttribute('class', 'spalteQuiz')
document.body.append(spalteQuiz)

for (let i = 0; i < quizDyn.length; i++) {
  const neuesQuiz = document.createElement('div')
  neuesQuiz.setAttribute('class', 'quiz')
  const aktuellesQuiz = document.getElementById('pOut')

  const neueFrage = document.createElement('p')
  neueFrage.setAttribute('class', 'frage')
  neueFrage.setAttribute('id', 'frage ' + (i + 1) + ' frage')
  neueFrage.setAttribute('name', 'frage ' + (i + 1) + ' frage')
  neueFrage.textContent = quizDyn[i].question
  const aktuelleFrage = document.getElementById('divOut')

  spalteQuiz.append(neuesQuiz)
  neuesQuiz.append(neueFrage)

  const frageTyp = quizDyn[i].type
  const anzahlAntworten = quizDyn[i].answerList.length
  const quidi = quizDyn[i].quid
  const quid = quizDyn.quid
  const entferneLeerzeichen = str => str.replace(/[\s,.]/g, '')

  // variable used for my array
  const loesung = []

  // function that's used for questions that are to be answered with checkboxes
  function istCheckbox () {
    // creating the <form>'s
    const form = document.createElement('form')
    form.setAttribute('name', 'frage' + quidi + 'form')
    neuesQuiz.append(form)

    // creating the <input>'s
    for (let i = 0; i < anzahlAntworten; i++) {
      const checkbox = document.createElement('input')
      checkbox.setAttribute('type', 'checkbox')
      checkbox.setAttribute('name', 'frage' + quidi + 'checkbox')
      checkbox.setAttribute(
        'id',
        entferneLeerzeichen(quizDyn[quidi - 1].answerList[i])
      )

      // creating the <label>'s
      const label = document.createElement('label')
      label.textContent = quizDyn[quidi - 1].answerList[i]
      label.setAttribute(
        'for',
        entferneLeerzeichen(quizDyn[quidi - 1].answerList[i])
      )

      // here i check if the checkbox is checked
      checkbox.addEventListener('change', function () {
        // if it's checked, push the checkboxes id to the array
        if (this.checked) {
          // loesung.push(this.id)
          // save this context for further use
          const answerString = this.id
          // re-add the space that was remove
          // THIS VERY CRUDE, CONSIDER NOT USING SPACES AT ALL!(!!!)
          const answerStringNew =
            answerString.substr(0, 6) +
            ' ' +
            answerString.substr(answerString.lastIndexOf('r') + 1)
          // filter question array to get index of element which includes the choosen answer in the answerList
          const quidElement = quizDyn.findIndex(el =>
            el.answerList.includes(answerStringNew)
          )
          // get the index of the answer in answerList
          const indexInAnswerList = quizDyn[quidElement].answerList.indexOf(answerStringNew)
          // push index to loesung
          loesung.push(indexInAnswerList)
        } else {
          // when unchecking, find the index of the unchecked checkbox'S id
          const index = loesung.indexOf(this.id)
          // splice 1 object at the position of index
          loesung.splice(index, 1)
        }
        // console log the array
        console.log(loesung)
      })

      // appending it all
      const zeilenUmbruch = document.createElement('br')
      form.append(checkbox)
      form.append(label)
      form.append(zeilenUmbruch)
    }
  }

  // there is more usually, because irelevant
  function istTyp () {
    istCheckbox()
  }

  istTyp()
}

But you could also use something like an data property to store the index when creating your element and just to use that, instead of reconstructing strings.

// Parse JSON
const quizDyn = JSON.parse(`[
  {
      "quid":1,
      "question": "question 1",
      "answerList":["answer 1_1","answer 1_2"],
      "solution":[1],
      "type":"checkbox"

  }, {
      "quid":2,
      "question": "question 2",
      "answerList":["answer 2_1","answer 2_2","answer 2_3"],
      "solution":[0,1,2],
      "type":"checkbox"
  }, {
      "quid":3,
      "question": "question 3",
      "answerList":["answer 3_1","answer 3_2","answer 3_3","answer 3_4"],
      "solution":[0],
      "type":"checkbox"
  }
]`)

// just creating a div here
const spalteQuiz = document.createElement('div')
spalteQuiz.setAttribute('class', 'spalteQuiz')
document.body.append(spalteQuiz)

for (let i = 0; i < quizDyn.length; i++) {
  const neuesQuiz = document.createElement('div')
  neuesQuiz.setAttribute('class', 'quiz')
  const aktuellesQuiz = document.getElementById('pOut')

  const neueFrage = document.createElement('p')
  neueFrage.setAttribute('class', 'frage')
  neueFrage.setAttribute('id', 'frage ' + (i + 1) + ' frage')
  neueFrage.setAttribute('name', 'frage ' + (i + 1) + ' frage')
  neueFrage.textContent = quizDyn[i].question
  const aktuelleFrage = document.getElementById('divOut')

  spalteQuiz.append(neuesQuiz)
  neuesQuiz.append(neueFrage)

  const frageTyp = quizDyn[i].type
  const anzahlAntworten = quizDyn[i].answerList.length
  const quidi = quizDyn[i].quid
  const quid = quizDyn.quid
  const entferneLeerzeichen = str => str.replace(/[\s,.]/g, '')

  // variable used for my array
  const loesung = []

  // function that's used for questions that are to be answered with checkboxes
  function istCheckbox () {
    // creating the <form>'s
    const form = document.createElement('form')
    form.setAttribute('name', 'frage' + quidi + 'form')
    neuesQuiz.append(form)

    // creating the <input>'s
    for (let i = 0; i < anzahlAntworten; i++) {
      const checkbox = document.createElement('input')
      checkbox.setAttribute('type', 'checkbox')
      checkbox.setAttribute('name', 'frage' + quidi + 'checkbox')
      checkbox.setAttribute(
        'id',
        entferneLeerzeichen(quizDyn[quidi - 1].answerList[i])
      )
      // add an data attribut
      checkbox.setAttribute('data-index', i)

      // creating the <label>'s
      const label = document.createElement('label')
      label.textContent = quizDyn[quidi - 1].answerList[i]
      label.setAttribute(
        'for',
        entferneLeerzeichen(quizDyn[quidi - 1].answerList[i])
      )

      // here i check if the checkbox is checked
      checkbox.addEventListener('change', function () {
        // if it's checked, push the checkboxes id to the array
        if (this.checked) {
          // loesung.push(this.id)
          // push data-index to loesung
          // this.dataset contains all attribuates 'data-'
          // but dataset only hold strings, so Number()
          // makes the index an integer again
          loesung.push(Number(this.dataset.index))
        } else {
          // when unchecking, find the index of the unchecked checkbox'S id
          const index = loesung.indexOf(this.id)
          // splice 1 object at the position of index
          loesung.splice(index, 1)
        }
        // console log the array
        console.log(loesung)
      })

      // appending it all
      const zeilenUmbruch = document.createElement('br')
      form.append(checkbox)
      form.append(label)
      form.append(zeilenUmbruch)
    }
  }

  // there is more usually, because irelevant
  function istTyp () {
    istCheckbox()
  }

  istTyp()
}

(I did not touch the uncheck function, since your question revolved around the index of the answerList array)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, that does make sense. I'll have to see and try to get the uncheck back to working correctly, with this, it removes the last object and not necessarily the one actually unchecked
1

I don't see the point of an event listener, here is my way of considering this code.

const quizDyn = 
  [ { quid: 1, question: 'question 1', answerList: ['answer 1_1', 'answer 1_2'],                             solution: [1],       type: 'checkbox' } 
  , { quid: 2, question: 'question 2', answerList: ['answer 2_1', 'answer 2_2', 'answer 2_3'],               solution: [0, 1, 2], type: 'checkbox' } 
  , { quid: 3, question: 'question 3', answerList: ['answer 3_1', 'answer 3_2', 'answer 3_3', 'answer 3_4'], solution: [0],       type: 'checkbox' } 
  ]
, spalteQuiz = document.createElement('div')
, quizForm   = document.createElement('form')
  ;
spalteQuiz.className = 'spalteQuiz'
spalteQuiz.append(quizForm)
document.body.append(spalteQuiz)

quizDyn.forEach((quiz,idxQuestion)=>
  {
  let field = document.createElement('fieldset')
  field.innerHTML = `<legend>${quiz.question}</legend>\n`
  quiz.answerList.forEach((answer,idxAnswer)=>
    {
    field.innerHTML += `<label><input name="${answer}" type="${quiz.type}" value="${idxQuestion}_${idxAnswer}">${answer}</label>\n`
    })
  quizForm.appendChild(field)
  })

quizForm.innerHTML += `<button type="submit"> verify </button> <button type="reset"> reset </button>`

quizForm.onsubmit = e =>
  {
  e.preventDefault()
  quizForm.querySelectorAll('input').forEach(answerX =>
    {
    let [quizN,answerN] = answerX.value.split('_').map(Number)
    answerX.closest('label').className = (answerX.checked === quizDyn[quizN].solution.includes(answerN) ) ? 'good' : 'bad'
    })
  }
quizForm.onreset = e =>
  {
  quizForm.querySelectorAll('label').forEach(lb=>lb.className = '')
  }
div.spalteQuiz fieldset {
  margin : .7em 0;
  width  : 20em;
  }
div.spalteQuiz label {
  display : block;
  float   : left;
  clear   : both;
  }
div.spalteQuiz label.bad {
  color:red;
  }
div.spalteQuiz label.good {
  color:green;
  }

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.