如何在AngularJS中观看Scope上的所有更改?

时间:2013-01-27 09:04:37

标签: javascript angularjs

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 个答案:

答案 0 :(得分:24)

我相信你不能注意$scope的变化(除了使用@ ValentynShybanov的消化)。你最接近的事情是观察摘要电话:

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

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

答案 1 :(得分: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");}
    );
}

答案 2 :(得分:3)

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

查看working 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 }

此解决方案可以满足您的需求,并且无需重构代码。

答案 3 :(得分:2)

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

<强> app.js

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

});

<强>的index.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>

这里的诀窍是通过&#39; true&#39;在$ watch函数的第三个参数中,它将执行angular.equal检查,该检查是按值检查而不是简单的引用检查。如果正确的话请告诉我。