Updating state of vuex array when one item has some changes
Asked Answered
V

5

29

I have an array called cases in my vuex store.

I want to update the array with the new content when I update a few fields within an existing item in the array.

I thought I could do something like this in my mutation but doesn't work and get the error typeError: undefined is not an object (evaluating 'state.objects.find')

EDIT_CASE (state, payload) {
    const item = state.objects.find(item => item.id === payload.recordId);
Object.assign(item, payload.case_status);

my array is as follows:

[
    {
        "case_name": "Laptop not working",
        "case_status": "live",
        "case_summary": "This is some summary content",
        "createdBy": "zippy",
        "createdDate": "2018-06-21T15:20:22.932Z",
        "id": "-LFXvk9yY5c-O8yIdf8k"
    },
    {
        "case_name": "Something else",
        "case_status": "live",
        "case_summary": "This is some summary content",
        "createdBy": "zippy",
        "createdDate": "2018-06-21T15:20:22.932Z",
        "id": "-STVvk9yY5c-O3yiTy8k"
    }
]

I also think from what I have read Vue does not observe changes within arrays so it may be I'm going completely the wrong way with this, and need to remove and then re-add the array item?

Basically I have a list, I make a change to my backend, now I want that list to reflect the changes I have made through updating the cases state, can anyone help?

Viens answered 3/7, 2018 at 8:16 Comment(1)
Seems that payload or item is undefined? Because I think state.cases[payload.index] = payload.item; should work properly, so perhaps error is somewhere else.Rollet
C
43

There is no array issue with your example because you try to change an object property - not array element reference. The problem is in Object.assign(item, payload.case_status); - you should provide an object not just a field. (Also you said that array called cases but example has objects, maybe this is problem too);

So this should work:

EDIT_CASE (state, payload) {
    const item = state.objects.find(item => item.id === payload.recordId);
    Object.assign(item, payload);
}

The error:

undefined is not an object

I think, it is related to Object.assign because you pass field to it which is undefined probably.

P.S. There is small example to help you understand when array issue appears and when everything works fine. See code comments :)

new Vue({
  el: "#app",
  data: {
    todos: [
      { text: "Learn JavaScript" },
      { text: "Learn Vue" },
      { text: "Play around in JSFiddle" },
      { text: "Build something awesome" }
    ]
  },
  methods: {
    // work because object property is reactive
  	changeItemProperty() {
    	this.todos[3].text = "changedItemProperty";
    },
    // same reason, properties are reactive
    changeItemWithAssign() {
    	Object.assign(this.todos[3], { text: "changedItemWithAssign" });
    },
    // does not work, can not track changes in array
    // also this will break all attempts to change TEXT property in UI
    // because property becomes not reactive after this due to new object
    // try to changeItemProperty or  changeItemWithAssign - does not work!
    // changeItem2 will fix it :)
    changeItem() {
    	this.todos[3] = { text: "changedItem" }
    },
    // works
    changeItem2() {
    	Vue.set(this.todos, 3, { text: "changedItem2" });
    }	
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
  <div v-for="todo in todos" :key="todo.text">
     {{todo.text}}
  </div>
  <button @click="changeItemProperty">changeItemProperty(works)</button>
  <button @click="changeItemWithAssign">changeItemWithAssign(works)</button>
  <button @click="changeItem">changeItem(does not work!)</button>
  <button @click="changeItem2">changeItem2(works)</button>
</div>
Cognomen answered 3/7, 2018 at 11:7 Comment(1)
Your example is very amazingly correct. I even tried to use it inside Vuex mutations and it works fine.Noblesse
G
8

JavaScript (not specific to Vue) can not detect setting the value of an Array item directly by index arr[3] = 'stop'; It also can not detect adding a new key or deleting an existing key from an Object. You must be defining the initial state of the store, e.g.

const store = new Vuex.Store({
  state: {
    objects: []
  },
  mutations: {
    EDIT_CASE (state, payload) {
      const index = state.objects.findIndex(item => item.id === payload.id);
      if (index !== -1) state.objects.splice(index, 1, payload);
    }
  }
})
Gambetta answered 3/7, 2018 at 11:17 Comment(0)
V
2

you need update your Array

const store = new Vuex.Store({
  state: {
    objects: [
      {id: 1, someProps: 'blablabla'},
      {id: 2, someProps: 'ololololo'}
   ]
  },
  mutations: {
    EDIT_CASE (state, data) {
      const index = state.objects.findIndex(item => item.id === data.id);
      state.objects[index].someProps = data.newPropsValue;

      //this is for vue reaction
      state.objects.push('dog-nail');
      state.objects.splice(-1,1);
  }
})
Viens answered 10/6, 2019 at 18:6 Comment(0)
L
2

You can use Vue.set to make the new object reactive

  const store = new Vuex.Store({
  state: {
    objects: []
  },
  mutations: {
    EDIT_CASE (state, payload) {
      const index = state.objects.findIndex(item => item.id === payload.id);
      if (index !== -1) {
        Vue.set(state.objects, index, payload);
      }
    }
  }
});
Lemmy answered 21/5, 2020 at 11:14 Comment(0)
G
-2

I had a problem like that and I solved like below: // in the component

 computed: {

     data: {
         get() {
             this.$store.commit('updateData', this.$store.state.data)
             return this.$store.state.data;
         },
     }
 }

// in the store

 mutations: {
      updateData(state,item){
          store.state.data = item;
      }
  }

yes, it's very amazing.

Girand answered 3/12, 2020 at 21:33 Comment(1)
Your comment makes no sens to me, the question is about setting new value in array's objects of a store, you show a getter in computed values of a component... Your mutation is using a variable 'store' which is not defined in the scope of your mutation. And you do not explain why and how this might work. Furthermore it adds little to Max Sinev's really comprehensive solution, you may delete this answer before some one downvote it.Doglike

© 2022 - 2024 — McMap. All rights reserved.