Home > Net >  In Vue multiple question, reverse one question options cause all question options change
In Vue multiple question, reverse one question options cause all question options change

Time:01-25

It is a Vue application that shows questions with multiple options, in each question, there is a button to reverse the options.

The full code is as below :

<template>
  <div >
      <div  v-if="step==0">
        <div >
          <button type="button"   @click="step=1;handleQuestions(data)"><span>Next Step</span></button>
        </div>

        <div >

              <el-input type="textarea" :rows="12" placeholder="Please input" v-model="data"> </el-input>

              <div  >
                <div  v-for="(item, index) in defaultOptions" :key="index">
                    <div >
                      <el-input  placeholder="label" v-model="item.label"></el-input>
                      <el-input  placeholder="score" v-model="item.score"></el-input>
                    </div>
                </div>
              </div>
         </div>
      </div>

      <div  v-if="step==1">
          <div >
            <button type="button"   @click="step=0"><span>Previous Step</span></button>
          </div>
          <div  >
            
              <div  v-for="(question, index) in questions" :key="index">
                <div  >  
                  <span  >
                      <span > {{index   1}}. </span>
                      <!-- <InputEditor  :value="question.name" @input="updateEditor($event,'name')"></InputEditor> -->
                      <span > {{index   1}} {{  question.name  }} </span>
                      <i  @click="reserveOptions(index)"> </i>
                  </span>
                </div>             
                <el-radio-group  >
                    <el-radio v-for="(question, index2) in question.options" :key="index2" :label="question" style="width: 100%;">
                        {{ question.label }}
                    </el-radio>
                </el-radio-group>
              </div>
          </div>  
      </div>          

  </div>
</template>



<script >

export default {
  name: 'Editor',
  components: {  },
  data: function () {
    return {

      data:'',

      step:0,
      questions:[],

      defaultOptions:[
        {'label':'very bad','score':1},
        {'label':'not bad','score':0},
        {'label':'ok','score':1},
        {'label':'good','score':2},
        {'label':'best','score':3},
      ]
    }
  },

  methods: {

    handleQuestions(codes){
      let lines = codes.split('\n');
      let lineArray = [];
      let questions = [];
      for(let i=0;i<lines.length;i  ){
          let line = lines[i].trimStart();
          if(line ===  ''){
            console.log('empty line',i,line);
          }else{
            console.log('line',line);
            lineArray.push(line);
          }
      }
      console.log('lineArray',lineArray);
      
      for(let i=0;i<lineArray.length;i  ){
          let question = lineArray[i];
          questions.push({name:question,options: this.defaultOptions });          
      }
      this.questions = questions;
    },

    reserveOptions(index) {
      this.questions[index].options = this.questions[index].options.reverse();
    }, 


  }
}
</script>

enter image description here

In the first step, you can input some questions into the textarea components and then click the next button.

Sample Inputs :

  1. I can quickly tell when I'm angry

  2. I know how I look and behave when I’m angry

  3. I can clearly distinguish between different degrees of happiness

  4. I can tell the difference between being sad and being angry


In the second step, you will see the list of questions with reverse button

enter image description here

when clicking the reverse button, I expect the clicked question would reverse the options only in that specific question. However, in this app, all the questions have reversed the options.

enter image description here

so strange, all the questions have reversed the options.

CodePudding user response:

The way you are assigning the arrays, like this.questions = questions;, and options: this.defaultOptions leads to copying the same reference to each question's options array that's why every question is getting affected. So, create a new options array every time for each question.

Another thing, If I got your logic correctly, you are splitting the lines and creating questions from every new line. So, you don't need to create a lineArray first and then loop on them, and then push to the local questions variable. These seem confusing as well as passing references while copying arrays. If the ultimate goal is to push every new line to the questions data array then why not do it in the first loop?

I created a shallow copy of defaultOptions and then assign it to the question's options. If you have nestedness in your array or array is multidimensional, then created a deep copy instead.

Replace your handleQuestions method with this and it will work-

handleQuestions(codes) {
  let lines = codes.split("\n");
  for (let i = 0; i < lines.length; i  ) {
    let line = lines[i].trimStart();
    if (line === "") {
      console.log("empty line", i, line);
    } else {
      console.log("line", line);
      let options = [...this.defaultOptions]; // create TRUE copy
      this.questions.push({
        name: line,
        options: options
      });
    }
  }
},

CodePudding user response:

I did not see any issue with the code you posted and it is working fine. Here is the working demo. Can you please have a look and try to find the root cause of the issue you are facing.

new Vue({
  el: '#app',
  data: {
    questions:[
      {'name':'question 1', options:[{'label':'a'},{'label':'b'},{'label':'c'}]},
      {'name':'question 2', options:[{'label':'a'},{'label':'b'},{'label':'c'}]},
    ]
  },
  methods: {
    reserveOptions(index) {
      this.questions[index].options = this.questions[index].options.reverse();
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div  v-for="(question, index) in questions" :key="index">
    <div  >  
      <span  >
        <span > {{ question.name }}. </span>
        <button @click="reserveOptions(index)">Reverse the order</button>
      </span>
    </div>             
    <div  >
      <span v-for="(question, index2) in question.options" :key="index2" :label="question">
        {{ question.label }}
      </span>
    </div>
  </div>
</div>

Update : As per the author's comment, Deep drive in to the original code he pasted and found the culprit.

questions.push({name:question,options: this.defaultOptions });

This is the statement which is causing the issue, As all the options property in the questions array objects holding the same address. It is updating the source defaultOptions for all the question options.

To make it work, You can assign the deep copy of the defaultOptions and it will work like a champ. Change that statement to :

questions.push({name:question,options: structuredClone(this.defaultOptions) });

Live Demo :

new Vue({
  el: '#app',
  data: {
    step:0,
    data:'',
    defaultOptions:[
      {'label':'very bad','score':1},
      {'label':'not bad','score':0},
      {'label':'ok','score':1},
      {'label':'good','score':2},
      {'label':'best','score':3},
    ],
    questions:[]
  },
  methods: {
    reserveOptions(index) {
      console.log(this.questions[index].options);
      this.questions[index].options = this.questions[index].options.reverse();
    },
    handleQuestions(codes) {
      let lines = codes.split('\n');
      let lineArray = [];
      let questions = [];
      for(let i=0;i<lines.length;i  ){
        let line = lines[i].trimStart();
        if (line) {
          lineArray.push(line);
        }
      }

      for(let i=0;i<lineArray.length;i  ){
        let question = lineArray[i];
        questions.push({name:question,options: structuredClone(this.defaultOptions) });          
      }
      this.questions = questions;
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-if="step === 0">
    <button type="button"   @click="step=1;handleQuestions(data)"><span>Next Step</span></button>

    <div>
      <textarea rows="12" placeholder="Please input" v-model="data"></textarea>
      <div v-for="(item, index) in defaultOptions" :key="index">
        <input placeholder="label" v-model="item.label"/>
        <input placeholder="score" v-model="item.score"/>
      </div>
    </div>
  </div>

  <div v-if="step === 1">
    <div>
      <button type="button" @click="step = 0"><span>Previous Step</span></button>
    </div>
    <div v-for="(question, index) in questions" :key="index">
      <div>
        <span> {{index   1}}. </span>
        <span> {{index   1}} {{question.name}} </span>
        <button @click="reserveOptions(index)">Reverse</button>
      </div>
      <ul>
        <li v-for="(question, index2) in question.options" :key="index2" :label="question" style="width: 100%;">
          {{ question.label }}</li>
      </ul>
    </div> 
  </div>
</div>

  • Related