DerEd
DerEd

Reputation: 70

JS - Index of value; Arrays

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()
}

Upvotes: 1

Views: 84

Answers (2)

Mister Jojo
Mister Jojo

Reputation: 22320

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;
  }

Upvotes: 1

ethergeist
ethergeist

Reputation: 619

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)

Upvotes: 1

Related Questions