Discussion icon indicating copy to clipboard operation
Discussion copied to clipboard

$watch multiple keys?

Open BigBlueHat opened this issue 10 years ago • 10 comments

I'm likely Doing It Wrong, but I have several instances where I need changes to have happened to multiple variables prior to triggering a method. Currently, I check for the proper values (or any value) of the variables inside the triggered method, but that means my code still looks like:

this.$watch('user', function() {
  this.fetchData()
})
this.$watch('project', function() {
  this.fetchData()
});

What I'd hoped to do was:

this.$watch(['user', 'project'], function() {
  this.fetchData();
});

Perhaps I'm just being lazy, but that looks prettier anyway. :grinning:

BigBlueHat avatar Jun 15 '14 03:06 BigBlueHat

The second syntax doesn't clearly indicate what conditions should be met to trigger the callback: should it be && or ||? || is essentially the same with the first syntax. In the case of &&, since these two values can change independently at any time, you need to specify a time window for them to be considered "changed together." And you probably need to implement that logic yourself.

yyx990803 avatar Jun 16 '14 15:06 yyx990803

In Angular it was possible to combine$watch`like this:

$scope.foo = 10;
$scope.bar = 'hello';
$scope.$watch('foo+bar', callback);

But I think it was possible because of their dirty-checking mecanism.

Have you tried something like this ?

this.watched = [this.user, this.project];
this.$watch('watched', cb);

ayamflow avatar Jun 18 '14 13:06 ayamflow

@yyx990803 good points.

@ayamflow for my purposes, that worked. Here's what I've done so far, and it's saved a fetch:

this.watched = [this.user, this.project];
this.$watch('watched', function() {
  if (this.user && this.project) {
    this.fetchData();
  }
});

Going to try that in a few more places, but seems to do the trick for now.

Thanks!

BigBlueHat avatar Jul 03 '14 16:07 BigBlueHat

I have a related problem. I'm converting a Rivets app which uses an adapter to beautifully integrate with chrome.storage.

I was trying to achieve the same with Vue, and hoping there was a way to watch an object, and get the callback anytime there was a change in a property of the object.

  window.vm = new Vue
    el: '.options'
    data:
      options:  # by default
        'flavour': 'banana'
        'color': 'yellow'
        'size': 3
        'shape': 'square'
        'amount': 40
    created: ->
      chrome.storage.local.get @options, (results) =>
        @options = results
    watch:
      options: (changedProperties) -> chrome.storage.local.set(changedProperties)

However the watch callback only get's executed if the object itself is replaced like with @options = results. The callback never gets executed when a property changes as a result a binding like v-model="options.flavour".

Ideally one of the arguments in the watch callback should receive an object with the changes. So if for example the flavour had changed to "chocolate", changedProperties would contain the following object: {flavour: chocolate"}

franciscolourenco avatar Jan 14 '15 01:01 franciscolourenco

I think what you're looking for is the ability to 'deep' watch an object, which Vue can do, but you'll have to do it in the ready callback. See $watch in the guide

multimeric avatar Jan 14 '15 01:01 multimeric

@TMiguelT that is indeed what I was looking for, however some things don't behave as expected. For example, newVal and oldVal seem to be the same, if you look at the log and change options.a in this example: http://jsfiddle.net/4rrpwd75/3/

Besides that, is there a way to know which properties changed?

Thanks

franciscolourenco avatar Jan 14 '15 01:01 franciscolourenco

No if you want the new and old value of a single value I think you need to watch it directly.

multimeric avatar Jan 14 '15 02:01 multimeric

@yyx990803 do you think it is viable to improve the arguments which are passed into the callback when deep listening for changes in objects? Right now oldVal seems to be the same as newVal. Form my point of view it would be useful to receive an object which only contained the changes, but that might be too much to ask..

Should I open a bug report about oldVal and newVal being the same?

franciscolourenco avatar Jan 14 '15 20:01 franciscolourenco

Well oldVal and newVal are indeed the same object, it's just mutated. I think it is possible to improve the arguments provided to deep watch callbacks though.

yyx990803 avatar Jan 26 '15 18:01 yyx990803

@yyx990803 is there any progress (or a recommended workaround) with this aspect yet? I'm deep watching objects containing many children and really need a way of knowing which ones changed in the watch callback, scanning all the children for changes is a terrible performance hit.

Aranad avatar Mar 16 '17 20:03 Aranad