Discussion
Discussion copied to clipboard
$watch multiple keys?
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:
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.
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);
@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!
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"}
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
@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
No if you want the new and old value of a single value I think you need to watch it directly.
@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?
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 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.