Vuejs and Vue.set(), update array

224,256

Solution 1

VueJS can't pickup your changes to the state if you manipulate arrays like this.

As explained in Common Beginner Gotchas, you should use array methods like push, splice or whatever and never modify the indexes like this a[2] = 2 nor the .length property of an array.

new Vue({
  el: '#app',
  data: {
    f: 'DD-MM-YYYY',
    items: [
      "10-03-2017",
      "12-03-2017"
    ]
  },
  methods: {

    cha: function(index, item, what, count) {
      console.log(item + " index > " + index);
      val = moment(this.items[index], this.f).add(count, what).format(this.f);

      this.items.$set(index, val)
      console.log("arr length:  " + this.items.length);
    }
  }
})
ul {
  list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<div id="app">
  <ul>
    <li v-for="(index, item) in items">
      <br><br>
      <button v-on:click="cha(index, item, 'day', -1)">
      - day</button> {{ item }}
      <button v-on:click="cha(index, item, 'day', 1)">
      + day</button>
      <br><br>
    </li>
  </ul>
</div>

Solution 2

EDIT 2

  • For all object changes that need reactivity use Vue.set(object, prop, value)
  • For array mutations, you can look at the currently supported list here

EDIT 1

For vuex you will want to do Vue.set(state.object, key, value)


Original

So just for others who come to this question. It appears at some point in Vue 2.* they removed this.items.$set(index, val) in favor of this.$set(this.items, index, val).

Splice is still available and here is a link to array mutation methods available in vue link.

Solution 3

As stated before - VueJS simply can't track those operations(array elements assignment). All operations that are tracked by VueJS with array are here. But I'll copy them once again:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

During development, you face a problem - how to live with that :).

push(), pop(), shift(), unshift(), sort() and reverse() are pretty plain and help you in some cases but the main focus lies within the splice(), which allows you effectively modify the array that would be tracked by VueJs. So I can share some of the approaches, that are used the most working with arrays.

You need to replace Item in Array:

// note - findIndex might be replaced with some(), filter(), forEach() 
// or any other function/approach if you need 
// additional browser support, or you might use a polyfill
const index = this.values.findIndex(item => {
          return (replacementItem.id === item.id)
        })
this.values.splice(index, 1, replacementItem)

Note: if you just need to modify an item field - you can do it just by:

this.values[index].itemField = newItemFieldValue

And this would be tracked by VueJS as the item(Object) fields would be tracked.

You need to empty the array:

this.values.splice(0, this.values.length)

Actually you can do much more with this function splice() - w3schools link You can add multiple records, delete multiple records, etc.

Vue.set() and Vue.delete()

Vue.set() and Vue.delete() might be used for adding field to your UI version of data. For example, you need some additional calculated data or flags within your objects. You can do this for your objects, or list of objects(in the loop):

 Vue.set(plan, 'editEnabled', true) //(or this.$set)

And send edited data back to the back-end in the same format doing this before the Axios call:

 Vue.delete(plan, 'editEnabled') //(or this.$delete)
Share:
224,256

Related videos on Youtube

Johan Hoeksma
Author by

Johan Hoeksma

Updated on July 08, 2022

Comments

  • Johan Hoeksma
    Johan Hoeksma almost 2 years

    I'm new to Vuejs. Made something, but I don't know it's the simple / right way.

    what I want

    I want some dates in an array and update them on a event. First I tried Vue.set, but it dind't work out. Now after changing my array item:

    this.items[index] = val;
    this.items.push();
    

    I push() nothing to the array and it will update.. But sometimes the last item will be hidden, somehow... I think this solution is a bit hacky, how can I make it stable?

    Simple code is here:

    new Vue({
      el: '#app',
      data: {
      	f: 'DD-MM-YYYY',
        items: [
          "10-03-2017",
          "12-03-2017"
        ]
      },
      methods: {
        
        cha: function(index, item, what, count) {
        	console.log(item + " index > " + index);
          val = moment(this.items[index], this.f).add(count, what).format(this.f);
      		this.items[index] = val;
          this.items.push();
          console.log("arr length:  " + this.items.length);
        }
      }
    })
    ul {
      list-style-type: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
    <div id="app">
      <ul>
        <li v-for="(index, item) in items">
        <br><br>
          <button v-on:click="cha(index, item, 'day', -1)">
          - day</button>
          {{ item }}
          <button v-on:click="cha(index, item, 'day', 1)">
          + day</button>
        <br><br>
        </li>
      </ul>
    </div>

  • Borjante
    Borjante about 7 years
    As said in the docs, $set is just a pretty .splice(). This makes sense because like they say in the docs you should modify the array using it's methods.
  • Ferrybig
    Ferrybig over 6 years
    Pls don't combine tab indents with space indents, the size of a tab is apparently different on the SE app, making it hard to read your code
  • Kokodoko
    Kokodoko over 6 years
    What string do I need to provide as the 'index' ?
  • Martin Calvert
    Martin Calvert over 6 years
    @Kokodoko can you clarify what you are trying to do? If it is an array it should be a number for the index. A string would be if you are setting a field on an object.
  • Kokodoko
    Kokodoko over 6 years
    Ah ok, my IDE insisted it had to be a string, must be a glitch.
  • atilkan
    atilkan almost 6 years
    Vue.set is not for vuex. And this.$set deprecated.
  • Martin Calvert
    Martin Calvert almost 6 years
    @atilkan link? Vue reactivity page still shows this.$set as a suggested method. Also, the vuex docs still say the proper way to add reactive properties is Vue.set. vuex.vuejs.org/guide/…
  • atilkan
    atilkan almost 6 years
    @MartinCalvert It says "when adding property to object". That is Vue.set's main purpose, not related to only vuex. Deprecation, i read it on the link but now reading again, i don't fully understand it. stackoverflow.com/questions/36671106/…
  • Martin Calvert
    Martin Calvert almost 6 years
    @atilkan oh I see, yea so my example might have bad names, but I am using it in Vuex to add new properties to an object, Vue.set(some_object_in_state_tree, new_prop, new_value). The deprecated part is a good call out tho I'll edit my answer to use the globals.
  • Chilly Code
    Chilly Code over 5 years
    In my case the ES6 spread-operator for the push operation does not work proberly with vue
  • MiniGod
    MiniGod over 3 years
    "For all object changes" -- You only need to use Vue.set on objects if the key doesn't already exist. If you are sure that the object already has the key, then you can simply do object[key] = value.