14

Angular 的 $watch 函数允许在指定属性更改时触发事件,如下所示。当范围发生任何变化时,是否有类似的方法来监听事件?

// works
$scope.$watch("someval", function() { }, true);
$scope.$watch(function(scope){ return scope.someval; }, function() { }, true);

// doesn't work
$scope.$watch("this", function() { }, true);
$scope.$watch(function(scope){ return scope; }, function() { }, true);
4

4 回答 4

24

我相信您无法观察到$scope(除了使用@ValentynShybanov 的建议)的变化。您可以做的最接近的事情是观察摘要调用:

$scope.$watch(function() { 
    console.log("digest called"); 
});

每次$digest在作用域上调用 a 时都会调用上述函数,即使作用域的属性没有更改也是如此。

于 2013-01-27T22:03:28.723 回答
9

这并不简单,因为范围是一个普通的对象。那是您可以订阅所有事件的 Backbone,但为此您的模型应该扩展专有接口 - Backbone.Model. Angular 在其经典外观中摒弃了观察者模式。这是一个不同寻常的设计决定。基本上有一个循环,Angular 评估被观察的表达式,当它检测到与前一次迭代的差异时,它会通知观察者。一种非常有趣的方法,可能是观察者模式的唯一替代方案(除了可能还不常见的反应式编程)。

我建议使用一个函数作为监视表达式,它返回范围的哈希值。不幸的是,范围在某处包含循环引用,因此快速解决方案(例如JSON.stringify($scope)不起作用)。我写了快速而肮脏的概念证明。http://jsfiddle.net/ADukg/2544。您在其中输入的任何文本字段都会打印到控制台。字符串哈希函数取自此处Generate a Hash from string in Javascript/jQuery

function MyCtrl($scope) {
    $scope.$watch(
        function($scope) {return hash($scope);},
        function() {console.log("changed");}
    );
}
于 2013-04-26T18:26:09.860 回答
3

我自己遇到了这个问题,我用类似于@ValentynShybanov 的评论解决了这个问题,但并不完全相同。我的解决方案不需要您按照评论中的说明为所有属性添加前缀

看到一个工作 plunkr

var entireScope = {};
  for ( var i in $scope ){
    if ( i[0] !== '$' && i !== 'this' && i !== 'constructor'){
      console.log(i);
      entireScope[i] = $scope[i];
    }
  }

  $scope.entireScope = entireScope;

  $scope.$watch('entireScope', function( newValue, oldValue ){
   $log.info('entireScope has changed',newValue, oldValue);
  }, true);

如您所见,解决方案完全相同,但实际上它向范围添加了另一个属性,而不是替换您已有的结构。这个新属性代表整个范围(因此得名),您可以观看它。

我写的循环可能太通用了,你可以用自定义的初始化来替换它。例如:

$scope.entireScope = { 'someVal' : $scope.someVal }

这个解决方案可以满足您的需求,让您无需重构代码。

于 2014-09-27T21:08:34.850 回答
2

一个简单的解决方案可能是您应该只检查范围的变量,但它可能是对象。

应用程序.js

app.controller('MainController', ['$scope', function($scope){
   $scope.watchable = {
       'param1':'',
       'param2':''
   };
   $scope.update = -1;
   $scope.$watch('watchable', function(scope){
       scope.update++;
   }, true);

});

索引.html

<div ng-controller="MainController">
    <input type='text' ng-model="watchable.param1">
    <input type='text' ng-model="watchable.param2">
    <p>param1:{{watchable.param1}}, param2:{{watchable.param2}}</p>
    <p>update:{{update}}
</div>

这里的技巧是在 $watch 函数的第三个参数中传递 'true' ,这将执行 angular.equal 检查,这是按值检查而不是简单的引用检查。请让我知道它是否正确。

于 2014-08-04T18:48:04.453 回答