Vue.js - Detect Nested Property Value Changes

vue watch object
vue watch dynamic property
vue set nested object
vue data object
vue data array
vue observer to object
vuex reactivity
js detect changes in object

I'm dynamically binding to an Array of objects in a Vue.js 2.0 app. I want to respond to changes as values in that Array change. At this time, as shown in this Fiddle, I have the following:

html

<div id="app">
  <table>
    <thead>
      <tr>
        <th v-for="(col, index) in cols">
          <input :placeholder="col.title" v-model="inputValues[col.prop]" />
        </th>        
      </tr>
    </thead>

    <tbody>
      <tr v-for="(item, index) in items">
        <td>{{ item.name }}</td>
        <td>{{ item.age }}</td>
        <td>{{ item.birthday }}</td>
      </tr>
    </tbody>
  </table>

  <hr />
  <textarea>{{ inputValues }}</textarea>
</div>

javascript

new Vue({
  el: '#app',
  data: {
    cols: [
      { title: 'Name', prop:'name' },
      { title: 'Age', prop:'age' },
      { title: 'Birthday', prop:'birthday' },      
    ],

    inputValues: [],

    items: [
      { id:1, name:'Andreas Winchell', age:47, birthday:'08-04-1970' },
      { id:2, name:'Victoria Hodges', age:80, birthday:'01-24-1937' },      
      { id:2, name:'James Morris', age:59, birthday:'06-14-1958' },      
      { id:2, name:'Larry Walker', age:68, birthday:'08-07-1949' },      
      { id:2, name:'Lee Maynard', age:46, birthday:'04-17-1971' } 
    ]
  },

  methods: {
    buttonClick: function() {
      alert(JSON.stringify(this.inputValues));
    }
  }
})

I can't seem to find a way to bind to changes in any of the values entered into the header. How do I detect and react to property values changes in an Array?

inputValues should be an object, not an array.

data: {
  cols: [
    { title: 'Name', prop:'name' },
    { title: 'Age', prop:'age' },
    { title: 'Birthday', prop:'birthday' },      
  ],
  // inputValues should be an object.    
  inputValues: {name: null, age: null, birthday: null },

  items: [
    { id:1, name:'Andreas Winchell', age:47, birthday:'08-04-1970' },
    { id:2, name:'Victoria Hodges', age:80, birthday:'01-24-1937' },      
    { id:2, name:'James Morris', age:59, birthday:'06-14-1958' },      
    { id:2, name:'Larry Walker', age:68, birthday:'08-07-1949' },      
    { id:2, name:'Lee Maynard', age:46, birthday:'04-17-1971' } 
  ]
}

How to detect changes in nested data? - Vue Forum, The parent has a computed property derived from the nested data. if I watch this value, that watcher gets triggered when the child data changes. If you only need detect that some property changed, you can use the deep:  So you create a watcher for that property, but Vue doesn't seem to fire the watcher when the nested data changes. Here's how you solve this. You need to set deep to true when watching an array or object so that Vue knows that it should watch the nested data for changes.

You can use arrays in your data, but Vue will not detect direct changes to the array referencing an item by its index. Vue will detect changes made with push(), pop(), slice() etc.

Arrays like 'Cols' are a disaster. 'Name', 'Age' and 'Birthday' are code (property names), not data. You really don't want to be iterating over an array generating forms like this. Keep it simple and code your three inputs.

Reactivity in Depth, Vue cannot detect property addition or deletion. However, it's possible to add reactive properties to a nested object using the Vue.set(object, propertyName, value) However, new properties added to the object will not trigger changes. To also detect nested value changes inside Objects, you need to pass in deep: true in the options argument. Note that you don’t need to do so to listen for Array mutations. Note that you don’t need to do so to listen for Array mutations.

As stated here in the VueJS documentation.

Due to limitations in JavaScript, Vue cannot detect the following changes to an array:

When you directly set an item with the index, e.g.

vm.items[indexOfItem] = newValue

To overcome this, both of the following will accomplish the same as vm.items[indexOfItem] = newValue, but will also trigger state updates in the reactivity system:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

How to Watch Deep Data Structures in Vue (Arrays and Objects , You can also check out the Vue docs on using watchers. Thirdly, we'll dive into how you can watch nested data in arrays and objects. In Vue we can watch for when a property changes, and then do something in response to that change. A watcher will only fire when the prop's value changes, but we often need it to  It is ok to initialize a field as an empty object, and set it to a new object with nested structures later, because Vue will be able to walk the nested properties of this new object and observe them. Adding and Deleting Properties As mentioned above, Vue observes data by converting properties with Object.defineProperty.

Update Array and Object in Vuejs - Milad Meidanshahi, Similarly, Vue.js cannot pick up these changes. Due to limitations in JavaScript, Vue cannot detect the following changes to an array: properties to a nested object using the Vue.set(object, propertyName, value) method. Change Detection Caveats. Due to limitations in JavaScript, there are types of changes that Vue cannot detect. However, there are ways to circumvent them to preserve reactivity. For Objects. Vue cannot detect property addition or deletion.

Vue.js, Vue.js - Set, Get & Delete Reactive Nested Object Properties complex / nested objects in Vue.js so the properties are reactive and changes import Vue from '​vue' function setProp (obj, props, value) { const prop property of a javascript object without having to manually check if the property exists first. The value of vm.reversedMessage is always dependent on the value of vm.message. You can data-bind to computed properties in templates just like a normal property. Vue is aware that vm.reversedMessage depends on vm.message, so it will update any bindings that depend on vm.reversedMessage when vm.message changes. And the best part is that we’ve

Complete Vue.js 2 Web Development: Practical guide to building , Practical guide to building end-to-end web development solutions with Vue.js 2 Vue can, however, detect nested changes with the deep variable. Create a new watch key for structure, which is an object with two values, deep and handler​. Below are a few simple utility functions for setting, getting and deleting properties of complex / nested objects in Vue.js so the properties are reactive and changes are automatically tracked in the UI. In other words the dynamic object properties are automatically hooked into the Vue.js reactivity system.

Comments
  • What do you expect to happen when you enter text in the header? I expect, you really don't want an array for inputValues but an object. jsfiddle.net/odcxypx6/4
  • @Bert - Basically, I want to run a method so that I can apply some logic to the value as it changes. Kind of like a filter.
  • vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
  • Even if ts an object, how do I react to changes of the property values in the object. For example, let's pretend that the name property changes, how do I run a method when that's updated?
  • @ZachTempleton It depends. One way would be to watch that value. What do you want to do when it changes?
  • @ZachTempleton I just saw your comment on the question itself. Do you want to filter the table results based on information in the inputs?
  • How exactly do you expect v-model to work with the col.prop values in an array here?
  • I don't expect v-model to work against an array like that. You cannot use square brackets in v-model, and expect the changes to be reactive. But if the data is an array (ie. x anonymous items), we can't just tell him to turn it into an object. Some combination of v-on with push() and slice() will do it, once we know what he's trying to achieve :-)
  • You can use indexers in v-model, and the modified fiddle linked in my comment shows it. I expect that once the values are completed, OP will want to push the inputValues object into items (adding an id along the way) and then clear the inputValues object, but OP seems to just be having an issue getting his binding to work for now.