观看多个$ scope属性


Answers:


585

从AngularJS 1.3开始,有一个新方法称为$watchGroup观察一组表达式。

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

7
与$ watchCollection('[a,b]')有什么区别?
卡米尔·汤姆斯克(KamilTomšík),2015年

28
不同之处在于您可以使用适当的数组来代替看起来像数组的字符串
Paolo Moretti 2015年

2
我有一个类似的问题,但使用controllerAs模式。在我的情况下,修复程序包括在控制器名称的前面加上变量:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
morels 2015年

1
在Angular 1.6上,这似乎不适用于我。如果将控制台日志放在该函数上,则可以看到它仅通过newValuesoldValues作为运行一次undefined,同时分别观察属性是否照常运行。
亚历杭德罗·加西亚·伊格莱西亚斯

290

从AngularJS 1.1.4开始,您可以使用$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
});

这里的柱塞示例

这里的文件


109
请注意,第一个参数不是数组。这是一个看起来像数组的字符串。
MK Safi 2013年

1
谢谢你 如果它对我
有用

5
需要明确说明(花了我几分钟时间才意识到)$watchCollection旨在将对象传递给对象,并监视对象的任何属性的变化,而$watchGroup旨在将一系列单个属性传递给观察对象的变化。处理相似但不同的问题略有不同。!
Mattygabe

1
不知何故,当您使用此方法时,newValues和oldValues始终相等:plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
mostruash '16

谢谢。它解决了我的问题。使用$ watch是否有性能影响/问题?
Syed Nasir Abbas's

118

$watch 第一个参数也可以是一个函数。

$scope.$watch(function watchBothItems() {
  return itemsCombinedValue();
}, function whenItemsChange() {
  //stuff
});

如果您的两个组合值很简单,则第一个参数通常只是一个角度表达式。例如,firstName和lastName:

$scope.$watch('firstName + lastName', function() {
  //stuff
});

8
这似乎是一个用例,默认情况下它会被要求包含在框架中。即使是像这样简单的计算属性也fullName = firstName + " " + lastName需要传递一个函数作为第一个参数(而不是像那样的简单表达式'firstName, lastName')。Angular如此强大,但是在某些领域中,Angular可以在不损害性能或设计原则的情况下对开发人员更加友好。
XML

4
好吧,$ watch只是带有一个角度表达式,该表达式是在它调用的范围内评估的。所以你可以做$scope.$watch('firstName + lastName', function() {...})。您也可以只做两块手表:function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);。我在答案中添加了简单的案例。
安德鲁·乔斯林

“ firstName + lastName”中的加号是字符串连接。因此,角度只是检查现在的连接结果是否不同。
mb21 2012年

16
字符串串联需要一点点注意-如果将“ paran orman”更改为“ para norman”,则不会触发响应。最好在第一项和第二项之间放置一个“ \ t | \ t”之类的分隔符,或者只使用确定的JSON
Dave Edelhart 2012年

虽然amberjs很烂,但是它内置了此功能!听到那些有角的家伙。我猜手表是最合理的可行方法。
阿拉丁

70

这是一个与您实际工作的原始伪代码非常相似的解决方案:

$scope.$watch('[item1, item2] | json', function () { });

编辑:好的,我认为这更好:

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

基本上,我们跳过了json步骤,这似乎很愚蠢,但是没有它就无法工作。他们的关键是经常省略的第三个参数,它打开对象相等性,而不是引用相等性。然后,我们创建的数组对象之间的比较实际上可以正常进行。


我有一个类似的问题。这对我来说是正确的答案。
Calvin Cheng

如果数组表达式中的项不是简单类型,则两者都有一点性能开销。
无效

是的,它正在对组件对象进行全面的深度比较。可能是您想要的,也可能不是。请参阅当前批准的答案,以获取不使用现代角度进行完整深度比较的版本。
卡伦·泽尔斯

由于某种原因,当我尝试在数组上使用$ watchCollection时,出现了此错误,TypeError: Object #<Object> has no method '$watchCollection'但是此解决方案可帮助我解决问题!
abottoni

太酷了,您甚至可以观看对象中的值:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
Serge van den Oever 2014年

15

您可以使用$ watchGroup中的函数来选择作用域中对象的字段。

        $scope.$watchGroup(
        [function () { return _this.$scope.ViewModel.Monitor1Scale; },   
         function () { return _this.$scope.ViewModel.Monitor2Scale; }],  
         function (newVal, oldVal, scope) 
         {
             if (newVal != oldVal) {
                 _this.updateMonitorScales();
             }
         });

1
你为什么用_this?如果不明确定义范围,范围就不会进入功能吗?
sg.cc 2015年

1
我使用打字稿,给出的代码是编译结果。
张扬

12

为什么不简单地将其包装成一个forEach

angular.forEach(['a', 'b', 'c'], function (key) {
  scope.$watch(key, function (v) {
    changed();
  });
});

这与为合并值提供函数的开销大致相同, 而实际上不必担心值的组成


在这种情况下,log()将执行几次,对吗?我认为在嵌套$ watch函数的情况下不会。并且它不应该在解决方案中一次查看多个属性。
约翰·多伊

不可以,每个监视属性的每次更改仅执行一次日志。为什么会多次调用它?
埃里克·艾格纳

是的,我的意思是如果我们要同时观看所有这些内容,那将不会很好。
约翰·多伊

1
当然可以吗?我在我的项目中就是这样做的。changed()每当这两个属性中的任何更改时,都会调用。这与提供组合值的函数的行为完全相同。
埃里克·艾格纳

1
稍有不同之处在于,如果数组中的多个项目同时更改,则$ w​​atch仅会触发处理程序一次,而不是每次更改一次。
bingles

11

合并值的较为安全的解决方案可能是将以下内容用作$watch函数:

function() { return angular.toJson([item1, item2]) }

要么

$scope.$watch(
  function() {
    return angular.toJson([item1, item2]);
  },
  function() {
    // Stuff to do after either value changes
  });


4

怎么样:

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

2
如果没有第三个true参数to scope.$watch(如您的示例),listener()则会每次触发一次,因为匿名哈希每次都具有不同的引用。
Peter V.Mørch2014年

我发现此解决方案适用于我的情况。对我来说,它更像是:return { a: functionA(), b: functionB(), ... }。然后,我彼此检查返回的新值和旧值的对象。
RevNoah 2014年

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

当年龄和名字值都改变时,这里的函数将被调用。


2
同样要确保在这种情况下,不要使用angular传递给回调函数的newValue和oldValue参数,因为它们将是结果级联,而不仅仅是更改的字段
Akash Shinde 2015年

1

$watchGroup在1.3版中引入的Angular 使用它可以监视多个变量,单个$watchGroup$watchGroup将数组作为第一个参数,其中可以包含要监视的所有变量。

$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]);
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.