Reputation: 103
I am trying to use a Vue watcher on a computed object and it is not working at all. It works properly if it's just a string, but not if it's an object. I followed the Vue documentation but I am still getting nothing logged to the console when the object changes. The properties of the object and computed property are changing, as I have confirmed in Vue Tools. What am I doing wrong? Thanks
<v-btn small dark @click="test1.asdf = 'blah'">Test</v-btn>
data() {
return {
test1: {},
}
},
computed: {
test() {
return this.test1
}
},
watch: {
test: {
handler: function(val, oldVal) {
console.log(oldVal, val);
},
deep: true
}
}
Upvotes: 4
Views: 6950
Reputation: 1920
@BadCoder Objects and Arrays are pass by reference in JavaScript, not pass by value. This means that when you add a key to the object as you are you doing in your question, you're just adding to the same Object. It's contents have changed but your variable test1
is still referencing the original object and unaware that its contents have updated. The watcher doesn't pick this change up. You can add deep: true
to your watcher as another answerer has suggested, but this only watches for a couple of levels deep, so not ideal if you have a large object with lots of nested data. The most reliable way to trigger a watcher when dealing with arrays or objects is to create a new instance of that object. You can achieve this with object destructing.
Something like,
<v-btn small dark @click="test1 = { ...test1, asdf: 'blah'}">Test</v-btn>
works because you're creating a new object (using the previous objects attributes, plus anything new), triggering the watcher.
Upvotes: 0
Reputation: 568
Just tried by replacing the whole object. It works pretty well, and there is no need to initialize your object with the asdf
property in your data:
<v-btn small dark @click="test1 = { ...test1, asdf: 'blah'}">Test</v-btn>
The spread syntax ...test1
helps keeping other properties in the target object if there is any, so you can safely add the asdf
property without worrying about losing anything.
JSFiddle: https://jsfiddle.net/vh72a3bs/22/
Upvotes: 1
Reputation: 621
Try this code, its works fine
<template>
<div id="app">
{{ test1 }}
<hr />
<button @click="test1.asdf = 'blah'">Click</button>
</div>
</template>
<script >
export default {
data() {
return {
test1: { asdf: "HEY" },
};
},
computed: {
test() {
return this.test1;
},
},
watch: {
test: {
handler: function (val, oldVal) {
console.log(oldVal, val);
},
deep: true,
},
},
};
</script>
I'd guess in your case you should add .native
at end of your click event like this @click.native="test1.asdf = 'blah'"
Upvotes: 3