$ watch'ing用于Angular指令中的数据更改

时间:2012-12-20 21:39:26

标签: javascript angularjs angularjs-directive

如何在操作内部数据时触发Angular指令中的$watch变量(例如,插入或删除数据),而不是将新对象分配给该变量?

我目前正在从JSON文件加载一个简单的数据集。我的Angular控制器执行此操作,并定义了一些函数:

App.controller('AppCtrl', function AppCtrl($scope, JsonService) {
    // load the initial data model
    if (!$scope.data) {
        JsonService.getData(function(data) {
            $scope.data = data;
            $scope.records = data.children.length;
        });
    } else {
        console.log("I have data already... " + $scope.data);
    }

    // adds a resource to the 'data' object
    $scope.add = function() {
        $scope.data.children.push({ "name": "!Insert This!" });
    };

    // removes the resource from the 'data' object
    $scope.remove = function(resource) {
        console.log("I'm going to remove this!");
        console.log(resource);
    };

    $scope.highlight = function() {

    };
});

我有<button>正确调用$scope.add函数,新对象已正确插入$scope.data集。我每次点击“添加”按钮时,我设置的表都会更新。

<table class="table table-striped table-condensed">
  <tbody>
    <tr ng-repeat="child in data.children | filter:search | orderBy:'name'">
      <td><input type="checkbox"></td>
      <td>{{child.name}}</td>
      <td><button class="btn btn-small" ng-click="remove(child)" ng-mouseover="highlight()"><i class="icon-remove-sign"></i> remove</button></td>
    </tr>
  </tbody>
</table>

但是,当所有这些发生时,我设置的用于观看$scope.data的指令不会被触发。

我在HTML中定义我的标签:

<d3-visualization val="data"></d3-visualization>

与以下指令相关联(为问题健全性而修剪):

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            });
        }
    }
});

我在一开始就收到了"I see a data change!"消息,但是在我点击“添加”按钮后从未收到过消息。

当我只是在$watch对象中添加/删除对象时,如何才能触发data事件,而不是将全新数据集分配给data对象?< / p>

3 个答案:

答案 0 :(得分:217)

您需要启用深层对象脏检查。 默认情况下,angular仅检查您观察的顶级变量的引用。

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            }, true);
        }
    }
});

Scope。 $ watch函数的第三个参数启用深度脏检查,如果它设置为true。

请注意深度脏检查昂贵。因此,如果您只需要观看子数组而不是整个data变量,请直接观察变量。

scope.$watch('val.children', function(newValue, oldValue) {}, true);

版本1.2.x引入了$watchCollection

  

Shallow监视对象的属性,并在任何属性发生更改时触发(对于数组,这意味着要观察数组项;对于对象映射,这意味着要观察属性)

scope.$watchCollection('val.children', function(newValue, oldValue) {});

答案 1 :(得分:1)

我的版本指向使用jqplot绘制数据后的数据:

    app.directive('lineChart', function() {
        $.jqplot.config.enablePlugins = true;

        return function(scope, element, attrs) {
            scope.$watch(attrs.lineChart, function(newValue, oldValue) {
                if (newValue) {
                    // alert(scope.$eval(attrs.lineChart));
                    var plot = $.jqplot(element[0].id, scope.$eval(attrs.lineChart), scope.$eval(attrs.options));
                }
            });
        }
});

答案 2 :(得分:1)

因为如果你想要深入触发你的数据,你必须通过你的听众的第3个参数true。默认它是false并且你的功能将会发挥作用触发,仅当您的变量不会改变它的字段