Home > Blockchain >  How do I make one single array of all selected radio buttons in vuejs?
How do I make one single array of all selected radio buttons in vuejs?

Time:07-04

First of all, I am very new to vue. I just learned it in a crash course and google in a couple hours. so forgive me if this is obvious.

My Code from a vue cli: https://github.com/Cerezze/testSnowJoe/tree/main/vue-project

So I have a problem where I have to make a single array of all the groups of radio buttons. This array is supposed to be filled by the index of radio button groups and is supposed to represent whether they are changed or not (wether they are checked or not). They can only pick one per group, its a quiz.

The problem I am having is that, even though I feel Im using the correct logic, the array starts from [0,0,0,0,0], for every single group of radio buttons. Which means that I can only produce an array with a button mapping from one group or another. Below Ill walk through the code and explain further.

App.vue

Here is a simple component where I just import a json file. It is an array of objects and each object contains: an id, question, answer and an array of choices (for the radio buttons). I send the entire array as props to Panels.

<template>
    HELLO
    <Panels :questions="questions"/>
    </template>
    
    <script>
    import Panels from './components/Panels.vue';
    import data from './questions.json';
    
export default{
    data(){
      return{
        questions: data
      }
    },
    components: {
      Panels
    }
}
</script>

<style>
</style>

Panels.vue

This component iterates through the the array of objects in the json file and creates a Panel for each index in the json file. I send the question and the questionsArray to Panel.

<template>
<div v-for="question in questions">
    <Panel :question="question" :questionsArray="questions"/>
</div>
</template>

<script>
import Panel from './Panel.vue'

export default{
    name: 'Panels',
    props: {
        questions: Array
    },
    components: {
        Panel
    }
}
</script>

<style scope>
</style>

Panel.vue

This component just provides the panel layout and transfers the choices array and the json array to question.

<template>
<div class = "Panel">
    <div>
        <p>{{question.question}}</p>
        <Question :choices = "question.choices" :questionsArray = "questionsArray"/>
    </div>
</div>
</template>

<script>
import Question from './Question.vue';

export default{
    
    name: 'Panel',
    props: {
        question: Object,
        questionsArray: Array
    },
    components: {
        Question
    }
}
</script>

<style scope>
</style>

Question.vue

And here is where my troubles lie. As I explained above, I am attempting to collect a single array to represent what is clicked for every group of questions. I would like it to be a one to one array because I want to check whether a radio button is clicked or not.

When I tried testing by simply pushing to the array, for each group it would push content properly, then when I went to another group of radio buttons, the array would start from the initialization again and proceed to push.

<template>
<div v-for="choice in choices">
    <input type="radio" :id = "choice" @change="onChange($event)" v-model="mChoice" :name = "choices" :value = "choice">
    <label :for = "choice">{{choice}}</label><br>
</div>
<p>{{mChoice}}</p>
</template>

<script>
import { VueElement } from 'vue';

export default{
    name: 'Question',
    data(){
        return{
            mChoice: null,
            arr: [0,0,0,0,0]
        }
    },
    methods: {
        onChange(e){
            var data = e.target.value;

            let val = {
                idx: 0,
                correctAns: ""
            };

            let arr2 = [...this.arr];

            this.questionsArray.forEach((i, index) => {
                if(e.target.name == i.choices){
                    val.idx = index;
                    val.correctAns = i.correctAnswer;
                    arr2.splice(index, 1, val);
                    this.arr = [...arr2];
                }
            });
            console.log( this.arr);
        }
    },  
    props: {
        choices: Array,
        questionsArray: Array
    }
}
</script>

<style scope>
</style>

CodePudding user response:

Observations :

  • e.target.name will return the string of the choices with comma separated and i.choices will return the array of choices. Hence, below condition will always return false.

    this.questionsArray.forEach((i, index) => {
      if(e.target.name == i.choices) { // Will always return false.
      }
    }
    

    You have to join(',') choices array to make the comparison happen.

  • Another issue is that for each component, arr: [0,0,0,0,0] will be separate as we initialized it in each Question component which render dynamically. Hence, It is updating separate arr for each Question component.

    One workaround for this problem is to emit the val object to parent and then handle that updation logic in parent and then do splice in parent.

Here is the live Demo :

Vue.component('question', {
  data: function() {
    return {
      mChoice: null
    }
  },
  props: ['choices', 'questionsarray'],
  template: `<div><div v-for="choice in choices">
<input type="radio" :id="choice" @change="onChange($event)" v-model="mChoice" :name="choices" :value="choice">
<label :for="choice">{{ choice }}</label></div>
</div>`,
  methods: {
    onChange(e) {
      const data = e.target.value;
      const val = {
        idx: 0,
        correctAns: ""
      };
      
      this.questionsarray.forEach((i, index) => {
        if(e.target.name == i.choices.join(',')) {
          val.idx = index;
          val.correctAns = i.correctAnswer;
          this.$emit('radioselection', { val: val, index: index })
        }
      });
    }
  }
});

var app = new Vue({
  el: '#app',
  data: {
    arr: [0, 0, 0, 0, 0],
    questions: [
      {
        "id": 1,
        "question": "1. What is Chris's favorite shadow puppet?",
        "choices": [
          "Dog",
          "Rabbit",
          "Bird"
        ],
        "correctAnswer": "Bird"
      },
      {
        "id": 2,
        "question": "2. What is Chris's favorite pokemon?",
        "choices": [
          "Poliwhirl",
          "Pikachu",
          "Suicune",
          "Buzz Lightyear"
        ],
        "correctAnswer": "Poliwhirl"
      },
      {
        "id": 3,
        "question": "3. What is Chris's least favorite dance?",
        "choices": [
          "Chicken Dance",
          "All"
        ],
        "correctAnswer": "All"
      },
      {
        "id": 3,
        "question": "4. What is Chris's favorite color?",
        "choices": [
          "Rainbow",
          "Black",
          "Rock",
          "MegaMan",
          "Sprite"
        ],
        "correctAnswer": "Black"
      }
    ]
  },
  methods: {
    getVal({val, index}) {
      this.arr.splice(index, 1, val);
      console.log(this.arr);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-for="question in questions">
    <p>{{ question.question }}</p>
    <Question :choices="question.choices" :questionsArray="questions" @radioselection="getVal"/>
  </div>
</div>

  • Related