将大对象传递给指令的正确方法

时间:2015-12-10 17:05:07

标签: angularjs angularjs-directive

我有一个大数据结构,我想使用Angular指令显示。

{
  name: 'structure',
  groups: [{
    name: 'one group',
    entries: [{
      name: 'a',
      type: 'a'
    }, {
      name: 'b',
      type: 'a'
    }]         
  }, {
    name: 'other group',
    entries: [{
      name: 'c',
      type: 'b'
    }, {
      name: 'd',
      type: 'a'
    }]
  }]
}

目前,我的指令将整个对象包含为值:

<!-- main.html -->
<div ng-repeat="group in groups">
  <my-group group-data="{{group}}"></my-group>
</div>

<!-- group.html -->
<div ng-repeat="entry in group.entries>
  <my-entry entry-data="{{entry}}"></my-entry>
</div>

<!-- entry.html -->
<div ng-if="entry.type === 'a'>{{entry.name}}</div>

// directives.js
angular.module('my-module')
  .directive('my-group', function() {
     return {
       templateUrl:'group.html',
       link: function (scope, element, attributes) {
         scope.$watch(attributes.groupData, function(value) {
           scope.group = value;
         });
       }
     });
     // similar for my-entry

只要结构不变,这就有效。问题是,当范围中groups的某些条目的值发生变化时,更改会在main.html中传播并显示,但不会在group.htmlentry.html中传播。此外,整个对象都包含在DOM中,感觉不对。

我尝试在我的指令上使用scope: {group: '='},但后来我根本没有得到价值。我已经尝试使用attributes.$observe('group', function (value) { /* same impl */ })而不是scope.$watch,但这似乎将对象作为字符串接收,因此我无法在不解析它​​的情况下访问单个属性(这感觉更加错误)。

如何将对象树传递给指令,并观察它的变化?

1 个答案:

答案 0 :(得分:1)

您正在使用$ watch错误。 $ watch的参数必须是范围内变量的名称,或者是返回某个值的函数。此外,没有必要手动观察这个参数更好地使用指令范围:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
</head>

<body ng-app="my-module" data-ng-controller="myController">
    <div ng-repeat="group in groups">
        <my-group group-data="group"></my-group>
    </div>
    <button type="button" ng-click="changeEntryName()">Change</button>
    <script>
        var app = angular.module('my-module', [])
            .controller('myController', ['$scope', function($scope) {
                $scope.groups = [{
                    name: 'one group',
                    entries: [{
                        name: 'a',
                        type: 'a'
                    }, {
                        name: 'b',
                        type: 'a'
                    }]
                }, {
                    name: 'other group',
                    entries: [{
                        name: 'c',
                        type: 'b'
                    }, {
                        name: 'd',
                        type: 'a'
                    }]
                }];

                $scope.changeEntryName = function() {
                    $scope.groups[0].entries[0].name = 'Kowabunga!';
                };
            }])
            .directive('myGroup', function() {
                return {
                    templateUrl:'group.html',
                    scope: {
                        group: '=groupData'
                    }
                }
            })
            .directive('myEntry', function() {
                return {
                    templateUrl:'entry.html',
                    scope: {
                        entry: '=entryData'
                    }
                }
            });
    </script>
    <script type="text/ng-template" id="group.html">
        <div ng-repeat="entry in group.entries">
            <my-entry entry-data="entry"></my-entry>
        </div>
    </script>
    <script type="text/ng-template" id="entry.html">
        <div ng-if="entry.type === 'a'">{{entry.name}}</div>
    </script>
</body>
</html>