Watch multiple $scope attributes

JavascriptAngularjsEventsAngularjs Watch

Javascript Problem Overview


Is there a way to subscribe to events on multiple objects using $watch

E.g.

$scope.$watch('item1, item2', function () { });

Javascript Solutions


Solution 1 - Javascript

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 
});

Solution 2 - Javascript

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

Solution 3 - Javascript

$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
});

Solution 4 - Javascript

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.

Solution 5 - Javascript

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();
             }
         });

Solution 6 - Javascript

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.

Solution 7 - Javascript

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
  });

Solution 8 - Javascript

$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.

Solution 9 - Javascript

how about:

scope.$watch(function() { 
   return { 
      a: thing-one, 
      b: thing-two, 
      c: red-fish, 
      d: blue-fish 
   }; 
}, listener...);

Solution 10 - Javascript

$scope.$watch('age + name', function () {
  //called when name or age changed
});

Here function will get called when both age and name value get changed.

Solution 11 - Javascript

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]);
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGregView Question on Stackoverflow
Solution 1 - JavascriptPaolo MorettiView Answer on Stackoverflow
Solution 2 - JavascriptRăzvan Flavius PandaView Answer on Stackoverflow
Solution 3 - JavascriptAndrew JoslinView Answer on Stackoverflow
Solution 4 - JavascriptKaren ZillesView Answer on Stackoverflow
Solution 5 - JavascriptYang ZhangView Answer on Stackoverflow
Solution 6 - JavascriptEraView Answer on Stackoverflow
Solution 7 - JavascriptguykView Answer on Stackoverflow
Solution 8 - JavascriptArtem AndreevView Answer on Stackoverflow
Solution 9 - JavascriptwacamoView Answer on Stackoverflow
Solution 10 - JavascriptAkash ShindeView Answer on Stackoverflow
Solution 11 - JavascriptVinit SolankiView Answer on Stackoverflow