Is there a way to subscribe to events on multiple objects using $watch
E.g.
$scope.$watch('item1, item2', function () { });
Is there a way to subscribe to events on multiple objects using $watch
E.g.
$scope.$watch('item1, item2', function () { });
Starting from AngularJS 1.3 there's a new method called $watchGroup
for observing a set of expressions.
$scope.foo = 'foo';
$scope.bar = 'bar';
$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
// newValues array contains the current values of the watch expressions
// with the indexes matching those of the watchExpression array
// i.e.
// newValues[0] -> $scope.foo
// and
// newValues[1] -> $scope.bar
});
$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
–
Alroy newValues
and oldValues
as undefined
, while individually watching the properties work as usual. –
Narcotize Beginning with AngularJS 1.1.4 you can use $watchCollection
:
$scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
// do stuff here
// newValues and oldValues contain the new and respectively old value
// of the observed collection array
});
Plunker example here
Documentation here
$watchCollection
is intended to be handed an object and provide a watch for changes to any of the object's properties, whereas $watchGroup
is intended to be handed an array of individual properties to watch for changes to. Slightly different to tackle similar yet different problems. Phew! –
Armhole $watch
first parameter can also be a function.
$scope.$watch(function watchBothItems() {
return itemsCombinedValue();
}, function whenItemsChange() {
//stuff
});
If your two combined values are simple, the first parameter is just an angular expression normally. For example, firstName and lastName:
$scope.$watch('firstName + lastName', function() {
//stuff
});
fullName = firstName + " " + lastName
requires passing a function as the first argument (rather than a simple expression like 'firstName, lastName'
). Angular is SO powerful, but there are some areas where it can be enormously more developer-friendly in ways that don't (seem to) compromise performance or design principles. –
Mononucleosis $scope.$watch('firstName + lastName', function() {...})
. You could also just do two watches: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);
. I added the simple case to the answer. –
Scorpio Here's a solution very similar to your original pseudo-code that actually works:
$scope.$watch('[item1, item2] | json', function () { });
EDIT: Okay, I think this is even better:
$scope.$watch('[item1, item2]', function () { }, true);
Basically we're skipping the json step, which seemed dumb to begin with, but it wasn't working without it. They key is the often omitted 3rd parameter which turns on object equality as opposed to reference equality. Then the comparisons between our created array objects actually work right.
TypeError: Object #<Object> has no method '$watchCollection'
but this solution helps me to solve my problem ! –
Stratfordonavon $scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
–
Territorial You can use functions in $watchGroup to select fields of an object in scope.
$scope.$watchGroup(
[function () { return _this.$scope.ViewModel.Monitor1Scale; },
function () { return _this.$scope.ViewModel.Monitor2Scale; }],
function (newVal, oldVal, scope)
{
if (newVal != oldVal) {
_this.updateMonitorScales();
}
});
_this
? Doesn't the scope get carried down into the functions without explicitly defining it? –
Kast Why not simply wrap it in a forEach
?
angular.forEach(['a', 'b', 'c'], function (key) {
scope.$watch(key, function (v) {
changed();
});
});
It's about the same overhead as providing a function for the combined value, without actually having to worry about the value composition.
changed()
is invoked whenever something changes in either of the properties. That's the exact same behavior as if a function for the combined value was provided. –
Drayman changed()
would be called three times. With something like $watchGroup
(or writing a function which combines the different values into a key), it would only be called once. –
Falkirk A slightly safer solution to combine values might be to use the following as your $watch
function:
function() { return angular.toJson([item1, item2]) }
or
$scope.$watch(
function() {
return angular.toJson([item1, item2]);
},
function() {
// Stuff to do after either value changes
});
$watch first parameter can be angular expression or function. See documentation on $scope.$watch. It contains a lot of useful info about how $watch method works: when watchExpression is called, how angular compares results, etc.
how about:
scope.$watch(function() {
return {
a: thing-one,
b: thing-two,
c: red-fish,
d: blue-fish
};
}, listener...);
true
parameter to to scope.$watch
(as in your example), listener()
would fire every single time, because the anonymous hash has a different reference every time. –
Winy return { a: functionA(), b: functionB(), ... }
. I then check the returned objects of the new and old values against each other. –
Zone $scope.$watch('age + name', function () {
//called when name or age changed
});
Here function will get called when both age and name value get changed.
Angular introduced $watchGroup
in version 1.3 using which we can watch multiple variables, with a single $watchGroup
block
$watchGroup
takes array as first parameter in which we can include all of our variables to watch.
$scope.$watchGroup(['var1','var2'],function(newVals,oldVals){
console.log("new value of var1 = " newVals[0]);
console.log("new value of var2 = " newVals[1]);
console.log("old value of var1 = " oldVals[0]);
console.log("old value of var2 = " oldVals[1]);
});
© 2022 - 2024 — McMap. All rights reserved.