angularjs指令监视没有触发对象函数属性

时间:2014-10-19 10:49:10

标签: javascript angularjs

TL; DR:当属性为函数时,更新被监视对象的属性似乎不会触发监视。

实例

请参阅this Plnkr exampl

单击示例中的按钮可以更改config对象的属性。对象是同步的(在指令和控制器之间),并且当属性发生更改时,将调用指令中的$watch函数(在这种情况下简单地计算计数器)。 除了更改函数属性时,这是我不明白的。

死的例子

视图

<main-dir config="configObject"></main-dir> 

指令

myApp.directive('mainDir', function () {

    return {
        restrict: 'E',
        scope: {config: '='},
        link: function (scope, el) {

            //(initialisation code)

            scope.$watch("config", function (config) {
                if (!config) return;
                // do stuff with config object
            }, true);

         }
     };
 });   

控制器

//init:
$scope.configObject = {
    propA: "value",
    propB: [1,2,3],
    propC: {key0: 3, key1: "value"},
    propD: function(x) {return x+1;}
}

//elsewhere:
$scope.configObject.propA = "other value"; //fires watch in directive
//or
$scope.configObject.propB = [3,2,1]; //fires watch in directive
//or
$scope.configObject.propB.push(5); //fires watch in directive
//or
$scope.configObject.propC = {key0: 1, key2: 34}; //fires watch in directive
//or
$scope.configObject.propC["key100"] = "newValue"; //fires watch in directive
//
// ... BUT ...
//
$scope.configObject.propD = function (x) {return x+2;} //does NOT fire watch in directive

因此,简而言之:我可以让$watch触发对象属性的更改。但是,如果属性是一个函数,那似乎不起作用。

解决方法:
当更改作为函数的属性时,我添加一行更改非函数属性以触发监视,如下所示:

$scope.configObject.propD = function (x) {/*...new function def...*/};
$scope.configObject.xxx = Math.random(); //<-- causes watch to fire

有谁知道为什么会这样?我是否可以在配置对象的 function 属性更改时触发$watch

谢谢!

1 个答案:

答案 0 :(得分:1)

范围。$ watch(“config.propD”)将观察函数的引用而不是返回值 范围。$ watch(“config.xxx”)将监视Math.random的返回值,因为您调用了函数

最简单的方法是使用$ watchCollection documentation,但它不是完美的

  scope.$watchCollection('config',
    function(config) {
      scope.caught++;
    }
  );

另一种方法是对$ watch'ers的收集进行编程,它的工作稍微好一些:

  angular.forEach(scope.config, function(value, key) {
    scope.$watch(function() {
      return scope.config[key];
    }, function(config) {
      scope.caught2++;
    }, true);
  });