Sensanaty
Sensanaty

Reputation: 1106

Vue editing v-data that has been passed to a component as a prop

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

Answers (2)

tony19
tony19

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))
    }
  }
}

demo

Upvotes: 2

saibbyweb
saibbyweb

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

Related Questions