Sebastián Grignoli
Sebastián Grignoli

Reputation: 33432

Items added to list are non-reactive in version 2 of Vue.js

In Vue 1.0 I used to add items to an array used in a v-for by simply calling items.push({}) as you can see here:

http://jsbin.com/figiluteni/1/edit?html,js,output

The exact same code in Vue 2.0 inserts a non-reactive object to the array:

http://jsbin.com/zuwihahiwa/1/edit?html,js,output

(Note that the newly added items are not live updated when edited)

    <button @click="items.push({})">Add item</button>

I know that Vue inserts hooks on arrays when initialized, but being a Vue model binding that creates the new item's "name" property, I thought it could be automatically hooked like in Vue 1.

I find this new behavior very inconvenient, for it forces me to add a prototype of the object I want to add in Vue's data and clone it:

http://jsbin.com/bamasobuti/1/edit?html,js,output

In Vue's data:

    item_prototype: {id: null, name: ""} 

In the template:

    <button @click="items.push(_.clone(item_prototype))">Add item</button>

My question is: Is there a recommended way of adding elements without having to keep a prototype of an empty element?

Upvotes: 1

Views: 1372

Answers (2)

Sebasti&#225;n Grignoli
Sebasti&#225;n Grignoli

Reputation: 33432

According Vue's documentation, v-model="item.prop" is just syntactic sugar for:

v-bind:value="item.prop" v-on:input="item.prop = $event.target.value".

To make it work, just stop using v-model="item.prop" and use this instead:

:value="item.prop" @input="$set(item,'prop',$event.target.value)"

Upvotes: 1

Evan You
Evan You

Reputation: 2711

The change is not related to reactivity system change, but rather how v-model works in 2.0: it no longer magically creates non-existent paths and make them reactive for you.

This change is intended to force you to think about your data shape and to make your application state more predictable, similar to how you are expected to declare the reactive properties in your component's data option.

If I were you, I'd create a method and just do this.items.push({ id: null, name: '' }). There's no need to clone it.

Upvotes: 2

Related Questions