Febertson
Febertson

Reputation: 474

Vue js watcher does not react to changes

I've seen some questions about vue.js watchers, but i didnt find a question handling my problem, so here it is:

In my SomeComponent.vue i use this code:

...
props: ['value']
,
watch: {
    value(val) {
        console.log(val);
    }
},

In my parent vue page, that uses this component i use this, which is working:

<template>
    <div>
        <SomeComponent
            v-model="test"
        ></SomeComponent>
    </div>
</template>
data() {
    return {
        test: {}
    };
},
created() {
    this.test = this.DoSomething();
},

If i add another property the watcher is not triggered anymore:

<template>
    <div>
        <SomeComponent
            v-model="test"
        ></SomeComponent>
    </div>
</template>
data() {
    return {
        test: {}
    };
},
created() {
    this.test.Prop1 = this.DoSomething();
    this.test.Prop2 = "Test";
},

EDIT: After Behappy's Answer my Component Part looks like this now:

...
props: ["value"],
watch: {
    value: {
        handler(val) {
            console.log(val);
        },
        deep: true
    }
},

Upvotes: 2

Views: 2251

Answers (2)

palaѕн
palaѕн

Reputation: 73906

As mentioned in the docs:

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. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive. For example:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` is now reactive

vm.b = 2
// `vm.b` is NOT reactive

Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the this.$set(object, propertyName, value) method:

In your case that would be:

created() {
    this.$set(this.test, 'Prop1', this.DoSomething())
    this.$set(this.test, 'Prop2', "Test")
},

Or, you can also assign a number of properties to an existing object, for example, using Object.assign() like:

this.test = Object.assign({}, this.test, { 'Prop1': 1, 'Prop2': 2 })

Upvotes: 3

BeHappy
BeHappy

Reputation: 3978

This is because your prop is an Object.

For deeply watching you can do this:

watch: {
    value: {
        handler(val) {
          console.log(val);
        },
        deep: true
    }
},

and in created DOM is not rendered yet. So prop you sent to child component is not updated yet.refer link

and as in other answers the correct way to change Object is to use this.$set:

  mounted() {
    this.$set(this.test, 'Prop1', this.DoSomething())
    this.$set(this.test, 'Prop2', 'Test')
  },

Upvotes: 4

Related Questions