Rei
Rei

Reputation: 37

Vue + vuex object mutations

I have a state:

state: {
  objects: [ 
    { 
      id: 10,
      key2: 'smth',
      key3: 'smth'
      //etc...
    },
    { 
      id: 12',
      key2: 'smth',
      key3: 'smth'
      //etc...
    }
  ]
}

I pick one by id and then i'm changing its keys via v-model.

getter

  activeObject: state => {
    return state.objects.find((obj) => obj.id === state.objId)
  }

in vue template

  computed: {
    obj() {
      return this.$store.getters.activeObject
    }
  },

in html

<input v-model="obj.key2"></input>

The problem is vuex tells me that i have to make changes in mutations only. I saw a many solutions like computed: get() set(), or _.deepClone or change only one key. but what i can do to rewrite entire object by id in mutation? My objects in array may be with many keys so write update commit func to every key will be very painful..

Is there a solution to rewrite object with many keys with 1 commit?

And please don't tell me to use lodash or other lbis, only plain vue/js.

Upvotes: 3

Views: 8618

Answers (1)

B M
B M

Reputation: 4019

Is there a solution to rewrite object with many keys with 1 commit?

Sure there is:

myMutation(state, { id, newItem }) {
    const item = state.objects.find(item => item.id === id);
    Object.assign(item, newItem);
}

//...
const params = { id: 23, newItem: myNewItem };
store.commit('myMutation', params);

Note that Vue does not observe changes inside arrays. It will not react to them.


Edit after OP added source code samples

What you are doing is against the "one way data flow" concept of Vuex. How to handle your use case is precisely explained in the Vuex docs:

Assuming obj is a computed property that returns an Object from the store, the v-model here will attempt to directly mutate obj.message when the user types in the input. In strict mode, this will result in an error because the mutation is not performed inside an explicit Vuex mutation handler. The "Vuex way" to deal with it is binding the 's value and call an action on the input or change event.

Thus using an event handler like

updateObj (e) { this.$store.commit('updateObj', e.target.value); }

That is called from your HTML code via

<input :value="message" @input="updateObj">

Note that as mentioned already, whether Vue will be able to see your changes on the stored Objects / Arrays depends on how you define them and how you access them, see Vuex mutations.

Upvotes: 4

Related Questions