Watch multiple $scope attributes

百般思念 提交于 2019-11-26 12:39:54

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

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

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

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.

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

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.

guyk

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.

wacamo

how about:

scope.$watch(function() { 
   return { 
      a: thing-one, 
      b: thing-two, 
      c: red-fish, 
      d: blue-fish 
   }; 
}, listener...);
$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]);
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!