Danny
Danny

Reputation: 7518

Vue array prop in child component not updating

I have a model from a backend where the property that normally contains an array of elements can be nullable. When this happens I'll init it to an empty array. However when doing that it seems to break my ability to update the array in the child component. Sample code can be found below.

Vue.component('Notes', {
 template: '<div>{{items}}<ul><li v-for="item in items">{{ item.text }}</li></ul><button @click="add">Add</button></div>',
 props: {
  items: Array,
 },
 methods: {
   add() {
    console.log('added');
    this.items.push({ text: "new item" });
   }
 }
});

new Vue({
 el: "#demo",
 data() { return { model: { }  }},
 created() { if(!this.model.items) this.model.items = []; }
});
<script src="https://unpkg.com/vue"></script>

<div id="demo">
  <Notes :items="model.items" />
</div>

If data in the main component is model: { items : [] } everything works fine. But I don't have control over the backend data to guarantee that.

Upvotes: 1

Views: 2500

Answers (2)

bbsimonbb
bbsimonbb

Reputation: 29002

In your Notes component, you declare a model in the data, then, just underneath, you add an items[] if one doesn't exist already. This is not a good practice, and could be the cause of your problems. Vue needs to know about all the properties on objects it's watching. They need to be there when Vue first processes the object, or you need to add them with Vue.set().

Upvotes: 1

Boussadjra Brahim
Boussadjra Brahim

Reputation: 1

You should emit an event to update the prop in the parent component

in child component :

 this.$emit('add-item',{
        text: "new item"
      });

in parent template add a handler for the emitted event :

  <Notes :items="model.items" @add-item="AddItem" />

Vue.component('Notes', {
  template: '<div>{{items}}<ul><li v-for="item in items">{{ item.text }}</li></ul><button @click="add">Add</button></div>',
  props: {
    items: Array,
  },
  methods: {
    add() {
      console.log('added');
      this.$emit('add-item', {
        text: "new item"
      });
    }
  }
});

new Vue({
  el: "#demo",
  data() {
    return {
      model: {
        items: [] //init it here in order to avoid reactivity issues
      }
    }
  },
  methods: {
    AddItem(item) {
      this.model.items.push(item)
    }
  },

});
<script src="https://unpkg.com/vue"></script>

<div id="demo">
  <Notes :items="model.items" @add-item="AddItem" />
</div>

Upvotes: 1

Related Questions