AngularJS:数据未通过属性传递到指令

时间:2016-12-19 07:43:42

标签: angularjs

在我的AngularJs(v1.5.9)应用程序中,我有一种列表视图指令,它本身依赖于指令来呈现单个复杂项目。在列表项中应该准确呈现的内容由消费者决定并通过翻译传递。

所以基本结构看起来像这样:

<list-directive>
  <list-item>
     <some more stuff />
     <transcluded content />
  </list-item>
</list-directive>

我现在正在尝试向此结构添加另一个指令,该指令将可以通过属性从外部传递到顶级元素的数据,然后根据每个列表项的输入执行操作

结构有点复杂,我试图将下面的代码片段减少到最低限度。

&#13;
&#13;
// controller
(function () { 
  'use strict';

    function FcDataListCtrl($scope, $q, $element) {
        var that = this;

        initVars();
        init();

        function initVars() {
          that.actionButtons = that.actionButtons || [];
        }

        function init() {
        }
    }

    angular
        .module('controls.fcDataList.controller', [])
        .controller('fcDataListCtrl', FcDataListCtrl);
})();

(function () {
    'use strict';

    function FcDataList() {
        return {
            restrict: 'E',
            transclude: true,
            template: `<fc-data-list-item ng-repeat="item in ::fcDataList.items" item="::item">
        <div ng-transclude></div>
    </fc-data-list-item>`,
            scope: {
                items: '=?',
                actionButtons: '=?'
            },
            controller: 'fcDataListCtrl',
            controllerAs: 'fcDataList',
            bindToController: true
        };
    }

 angular
     .module('controls.fcDataList', [
            'controls.fcDataList.controller',
            'controls.fcDataList.item'
        ])
        .directive('fcDataList', FcDataList);
})();

(function () {
    'use strict';

    function FcDataListItem() {
        return {
            restrict: 'E',
            replace: true,
            require: '^fcDataList',
            transclude: 'element',
            template: `<div>
                          <div ng-transclude></div>
                          <fc-item-menu items="fcDataList.actionButtons"></fc-item-menu>
                      </div>`,
            scope: {
                item: '=?'
            },
            link: {
                pre: FcDataListItemLink
            }
        };

        function FcDataListItemLink(scope, elem, attrs, fcDataListCtrl) {
            initVars();
            init();

            function initVars() {
            }

            function init() {
              console.log('FcDataListItem')
              console.dir(fcDataListCtrl.actionButtons);
            }
        }
    }

    angular
        .module('controls.fcDataList.item', [
      'components.fioControlsExtensions.fcDataList.menu'
    ])
        .directive('fcDataListItem', FcDataListItem);
})();

(function () {
    'use strict';

    function FcItemMenu() {
        return {
            restrict: 'E',
            template: `<div ng-repeat="item in items">
    <div>{{ item.icon }}</div>
</div>`,
            scope: {
                items: '=?'
            },
            link: {
                pre: FcItemMenuLink
            }
        };

        function FcItemMenuLink(scope, elem, attrs) {
            scope.open = open;
            initVars();
            init();

            function initVars() {
              console.log('MenuItem');
              console.dir(scope.items);
            }

            function init() {
            }

            function open(event) {
            }
        }
    }

    angular
        .module('components.fioControlsExtensions.fcDataList.menu', [])
        .directive('fcItemMenu', FcItemMenu);
})();



(function () {
    'use strict';

    function AppCtrl() {
        var that = this;

        init();

        function init() {
            that.fcDataList = {
                
                buttons: [
                    { icon: 'ff-show' }
                ],
                
                items: [
                    { firstName: 'Ivan', lastName: 'Petrov', jobPosition: 'Zookeeper' },
                    { firstName: 'Andrei', lastName: 'Müller', jobPosition: 'Pilot' },
                    { firstName: 'Christian', lastName: 'Klein', jobPosition: 'Cook' },
                    {  firstName: 'Peter', lastName: 'Stoyanov', jobPosition: 'Fuller' },
                    { firstName: 'Nadine', lastName: 'Wolf', jobPosition: 'Driving Instructor' },
                    { firstName: 'Amya', lastName: 'Krüger', jobPosition: 'Military' }
                ],
        }       
    }
}

    angular
        .module('controls.example', [
      'controls.fcDataList'
    ])
        .controller('AppCtrl', AppCtrl)

})();
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<html lang="en" ng-app="controls.example">
<body ng-controller="AppCtrl as app">
  <b>Test for data list n stuff</b>
  <fc-data-list items="app.fcDataList.items"
                action-buttons="app.fcDataList.buttons">
      <div class="row">
        <span> This is a list item </span>
    </div>
  </fc-data-list>
</body>
</html>
&#13;
&#13;
&#13;

这里也是Codepen的例子:https://codepen.io/lyioth/pen/LbqWLz/

请注意,这里没有显示实际项目内容的转换(但这没有问题,所以我跳过了它。)

实际问题是,items中的fc-item-menu未定义。我添加了一些日志语句来表明在该组件上面的级别,所讨论的数组实际上并不是空的。

如果我将指令更改为require控制器并直接访问actionButtons属性,它似乎也可以工作。但我宁愿不这样做。

所以问题是,为什么这项工作没有按预期进行?我错过了什么?

1 个答案:

答案 0 :(得分:1)

items处的fc-item-menu绑定到fcDataList.actionButtons。这意味着fc-item-menu指令将在 scope.fcDataList.actionButtons 中查找它们。

让我们退一步 - 在你的fc-data-list指令中,你有相同类型的绑定 - fcDataList.item。这是有效的,因为您使用了bindToControllercontrollerAs,它将隔离的范围放在范围字段中,其名称在controllerAs中定义( scope.fcDataList )。

返回fc-item-menu:虽然指令中有 require:^ fcDataList ,但上面的表达式将是未定义的,因为不存在 scope.fcDataList 。此外,这是正确的,因为通过转换,已创建一个隔离的范围,该范围不包含 scope.fcDataList 。使其工作的方法是使用控制器中的值自己定义范围属性,如下所示:

function FcDataListItemLink(scope, elem, attrs, fcDataListCtrl) {
    scope.buttons = fcDataListCtrl.actionButtons;
}

这是一个有效的plnkr:https://codepen.io/anon/pen/GNzELy