Reputation: 1106
I'm using Nuxt 2.15.3
.
In my app, users can set up Questions that their customers can answer, and the questions can be a variety of types, one of them being a Multiple Choice question. These types of questions have a title, as well as multiple answer options that people can choose from.
On my Questions page, I list all of the User's questions, and I want to allow them to edit any question, but I'm having some trouble figuring out how to do that exactly, at least when it comes to editing multiple choice questions. As it stands currently, I have a EditQuestion
component to which I pass a question
prop from my QuestionCard
component, the prop just being the details of the question which is stored in Vuex.
My current (simplified for SO) version of the EditQuestion
component:
<template>
<input v-model="questionTitle" type="text">
<div v-if="question.type === 'multiple_choice'">
<input v-for="option in questionOptions" v-model="option.content" type="text">
</div>
<button @click.prevent="updateQuestion"></button>
</template>
<script>
export default {
props: {
question: {}
},
data() {
return {
questionTitle: this.question.title,
questionOptions: this.question.options
}
},
methods: {
updateQuestion() {
// Call the API with the new question details
}
}
}
</script>
If I were only editing question titles, this works great. However, my issue comes from the options. If I try to update one, Vuex warns me about mutating the store state outside of a mutation, and it warns me all the same even if I clone question.options
, for example by doing questionOptions: Object.assign({}, this.question.options)
or questionOptions: {...this.question.options}.
The part that confuses me is why Vuex doesn't complain when I modify the questionTitle
data object, and only when editing the questionOptions?
For reference if it's relevant, question.title
is just a simple string, while question.options
is an object that looks something like this:
{
"0": {
"id": 0,
"content": "Option 1"
},
"1": {
"id": 1,
"content": "Option 2"
}
}
What is the best way for me to allow people to edit the Multiple Choice question options?
Upvotes: 4
Views: 275
Reputation: 138346
In JavaScript, primitives (String
, Number
, BigInt
, Boolean
, undefined
, and null
) are copied by value, while objects (including Array
, Map
, WeakMap
, Set
, WeakSet
) are copied by reference.
this.question.title
is a String
, so it gets copied by value into the new variable. On the other hand, this.question.options
is an object (it looks like an Array
), so it's copied by reference into questionOptions
, and thus questionOptions
and this.question.options
refer to the same object in Vuex.
Your idea of cloning the incoming this.question.options
is on the right track to a solution, but Object.assign()
and the spread operator only create shallow copies that still refer to the same original object, which explains the Vuex state-mutation warnings when your component tried to modify the shallow copy.
There are several ways to deep-copy an object, one of which is provided in the other answer here:
export default {
data() {
return {
questionTitle: this.question.title,
questionOptions: JSON.parse(JSON.stringify(this.question.options))
}
}
}
Upvotes: 2
Reputation: 3254
Try making a local copy of the question
object and do all the updates on that local copy only, something like this:
<script>
export default {
props: {
question: {}
},
data() {
return {
localCopyOfQuestion: JSON.parse(JSON.stringify(this.question)),
questionTitle: this.localCopyOfQuestion.title,
questionOptions: this.localCopyOfquestion.options
}
},
methods: {
updateQuestion() {
// Call the API with the new question details
}
}
}
</script>
Upvotes: 1