Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js props watch not working

Tags:

vue.js

Consider following trivial app:

<div id="app">
  <counters :counter1="counter1" :counter2="counter2">
  </counters>
  <button @click="onClick">Click Here</button>
</div>

JS:

Vue.component('counters', {
  template: '<h1>{{counter1.count}} {{counter2.count}}</h1>',
  //template: '<h1>{{count1}} {{count2}}</h1>',
  props: {
    'counter1': {
      type: Object
    },
    'counter2': {
      type: Object
    }
  },
  data: function() {
    return {
      'count1': 0,
      'count2': 0,
    }
  },
  watch: {
    counter1: function(n, o) {
      console.log(JSON.stringify(n));
      this.count1 = n.count;
    },
    counter2: function(n, o) {
      console.log(JSON.stringify(n));
      this.count2 = n.count;
    }
  }
});


var vm = new Vue({
  el: '#app',
  data: {
    counter1: {
      count: 0
    },
    counter2: {
      count: 0
    }
  },
  methods: {
    onClick: function() {
      this.counter1.count++;
      this.counter2.count++;
    }
  }
});

"counters" expects two props counter1 and counter2 , both objects. The properties counter1.count and counter2.count are used directly in template. On clicking the button both counters are incremented by one. This works flawlessly as can be seen here: jsfiddle

However I wanted to use "watch" for updating the counters. So I defined reactive properties count1 and count2 and updated them whenever counter1 and counter2 changed. For some reason this does not work. I was under impression both approaches should yield the same result although using watch is less efficient. But probably I am missing something here. Can you explain?

like image 372
kargirwar Avatar asked Mar 31 '18 08:03

kargirwar


2 Answers

If you want to watch for changes on an object you will need to use a deep watcher:

watch: {
  counter1: {
    handler(n, o) {
      this.count1 = n.count;
    },
    deep: true
  },
  counter2: {
    handler(n, o) {
      this.count2 = n.count;
    },
    deep: true
  }
}

Here's the JSFiddle: https://jsfiddle.net/osyam658/

Alternatively you may watch the object property itself, by wrapping the property name in quotes in the watcher:

  watch: {
    'counter1.count': function(n, o) {
      this.count1 = n;
    },
    'counter2.count': function(n, o) {
      this.count2 = n;
    }
  }

Here's the JSFiddle for that: https://jsfiddle.net/b7drpy7j/

like image 122
craig_h Avatar answered Nov 11 '22 00:11

craig_h


You need to setup up a deep watcher to observe changes nested inside objects as follows:

watch: {
  counter1: {
    handler: function(n, o) {
      console.log(JSON.stringify(n));
      this.count1 = n.count;
    },
    deep: true  
  },
  counter2: 
    handler: function(n, o) {
      console.log(JSON.stringify(n));
      this.count2 = n.count;
    },
    deep: true
  }
}

Here is the updated fiddle

Reference: deep option for vm.$watch()

like image 30
Vamsi Krishna Avatar answered Nov 10 '22 23:11

Vamsi Krishna