Skip to content
Advertisement

Vue How to Merge Two Arrays From Same Object?

I am pulling data from an API that gives me an object of items, each containing a string named correct_answer and an array named incorrect_answers.

I am trying to combine those values within each item, so when I do v-for, it will loop through the answers merged together in one loop. I also want to randomize the order of those answers.

An example of what the object looks like:

"results": [
    {
      "question": "Where was the Games of the XXII Olympiad held?",
      "correct_answer": "Moscow",
      "incorrect_answers": [
        "Barcelona",
        "Tokyo",
        "Los Angeles"
      ]
    },
    {
      "question": "What is the first weapon you acquire in Half-Life?",
      "correct_answer": "A crowbar",
      "incorrect_answers": [
        "A pistol",
        "The H.E.V suit",
        "Your fists"
      ]
    },
]

Advertisement

Answer

You could 1️⃣spread the incorrect_answers into a new array with correct_answer, and then 2️⃣ attach the result as a new property on the original data. Additionally, 3️⃣ you could shuffle the answers while you’re at it:

const newData = data.map(x => {
  const answers = [x.correct_answer, ...x.incorrect_answers] /*1️⃣*/
  x.answers /*2️⃣*/ = shuffle(answers) /*3️⃣*/
  return x
})

This new array could be used as a computed property (e.g., named questions) in your template:

<fieldset v-for="q in questions" :key="q.question">

const rawData = {
  "results": [
    {
      "question": "Where was the Games of the XXII Olympiad held?",
      "correct_answer": "Moscow",
      "incorrect_answers": [
        "Barcelona",
        "Tokyo",
        "Los Angeles"
      ]
    },
    {
      "question": "What is the first weapon you acquire in Half-Life?",
      "correct_answer": "A crowbar",
      "incorrect_answers": [
        "A pistol",
        "The H.E.V suit",
        "Your fists"
      ]
    },
  ]
}

new Vue({
  el: '#app',
  data() {
    return {
      rawData: rawData.results
    }
  },
  computed: {
    questions() {
      return this.rawData.map(x => {
        const answers = [x.correct_answer, ...x.incorrect_answers]
        x.answers = shuffle(answers)
        this.$set(x, 'answer', null) // create reactive answer prop
        return x
      })
    }
  }
})

// https://stackoverflow.com/a/2450976/6277151
function shuffle(array) {
  let currentIndex = array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }

  return array;
}
<script src="https://unpkg.com/vue@2.6.10"></script>

<div id="app">
  <form action="#">
    <fieldset v-for="(q,i) in questions" :key="q.question">
      <h2>{{q.question}} {{q.answer}}</h2>
      
      <div v-for="a in q.answers" :key="a">
        <label>
          <input type="radio" :name="i" :value="a" @change="q.answer = a">
          <span>{{a}}</span>
        </label>
      </div>
    </fieldset>
  </form>
</div>
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement