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>
In the first step, you can input some questions into the textarea components and then click the next button.
Sample Inputs :
I can quickly tell when I'm angry
I know how I look and behave when I’m angry
I can clearly distinguish between different degrees of happiness
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
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.
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>