I have an array called people
that contains objects as follows:
Before
[
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
It can change:
After
[
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 33},
{id: 2, name: 'Joe', age: 38}
]
Notice Frank just turned 33.
I have an app where I am trying to watch the people array and when any of the values changes then log the change:
<style>
input {
display: block;
}
</style>
<div id="app">
<input type="text" v-for="(person, index) in people" v-model="people[index].age" />
</div>
<script>
new Vue({
el: '#app',
data: {
people: [
{id: 0, name: 'Bob', age: 27},
{id: 1, name: 'Frank', age: 32},
{id: 2, name: 'Joe', age: 38}
]
},
watch: {
people: {
handler: function (val, oldVal) {
// Return the object that changed
var changed = val.filter( function( p, idx ) {
return Object.keys(p).some( function( prop ) {
return p[prop] !== oldVal[idx][prop];
})
})
// Log it
console.log(changed)
},
deep: true
}
}
})
</script>
I based this on the question that I asked yesterday about array comparisons and selected the quickest working answer.
So, at this point I expect to see a result of: { id: 1, name: 'Frank', age: 33 }
But all I get back in the console is (bearing in mind i had it in a component):
[Vue warn]: Error in watcher "people"
(found in anonymous component - use the "name" option for better debugging messages.)
And in the codepen that I made, the result is an empty array and not the changed object that changed which would be what I expected.
If anyone could suggest why this is happening or where I have gone wrong here then it would be greatly appreciated, many thanks!
It is well defined behaviour. You cannot get the old value for a mutated object. That's because both the
newVal
andoldVal
refer to the same object. Vue will not keep an old copy of an object that you mutated.Had you replaced the object with another one, Vue would have provided you with correct references.
Read the
Note
section in the docs. (vm.$watch
)More on this here and here.
I have changed the implementation of it to get your problem solved, I made an object to track the old changes and compare it with that. You can use it to solve your issue.
Here I created a method, in which the old value will be stored in a separate variable and, which then will be used in a watch.
See the updated codepen
Your comparison function between old value and new value is having some issue. It is better not to complicate things so much, as it will increase your debugging effort later. You should keep it simple.
The best way is to create a
person-component
and watch every person separately inside its own component, as shown below:Please find below a working example for watching inside person component. If you want to handle it on parent side, you may use
$emit
to send an event upwards, containing theid
of modified person.