自定义指令的控制器不适用于 ng-repeat?

The controller of custom directive doesn't work with ng-repeat?

我正在尝试构建 2 个自定义指令,my-tile 和 my-tile-item。

"my-tile" 是接受数据数组参数的主要指令。

"my-tile-item" 表示 "my-tile" 内的单个图块。

但是 my-tile-item 控制器的 btnOkClick() 方法不起作用。

代码:

https://codepen.io/anon/pen/zdWgVG

HTML:

<div my-tile tiles="mainCtrl.tiles"></div>

my-tile 模板:

<script type="text/ng-template" id="myTile.html">
    <div my-tile-item ng-repeat="tileItem in myTileCtrl.tiles" class="my-tile">
        <div>{{tileItem.id}}</div>
        <button ng-click="myTileItemCtrl.btnOKClick()">OK</button>
    </div>

</script>

my-title 指令:

angular.module('app').directive('myTile',
        [
            myTile
        ]);


    function myTile() {
       return {
           restrict: 'AE',
           scope: {
             tiles: '='
           },

           controller: ['$scope', MyTileController],
           controllerAs: 'myTileCtrl',


           templateUrl: 'myTile.html',

           link: function (scope, iElement, iAttrs) {
               console.log('abc');
           }
       };


       function MyTileController($scope) {
           var ctrl = this;
           ctrl.tiles = $scope.tiles;
       }

    }

my-tile-项目指令:

angular.module('app').directive('myTileItem',
        [
            myTileItem
        ]);


    function myTileItem() {
        return {
            restrict: 'AE',
            scope: {

            },

            controller : ['$scope', MyTileItemController],
            controllerAs : 'myTileItemCtrl',

            link: function (scope, iElement, iAttrs) {

            }
        };


        function MyTileItemController($scope) {
            var ctrl = this;

            ctrl.btnOKClick = function () {
                alert('OK Clicked'); // ********* does NOT work *************
            }
        }


    }
(function () {
    'use strict';

    angular.module('app').directive('myTileItem',
        [
            myTileItem
        ]);


    function myTileItem() {
        return {
            restrict: 'AE',
            link: function (scope, iElement, iAttrs) {
              scope.btnOKClick = function () {
                alert('OK Clicked');
            }
            }
        };
    }
})();

将 btnOnClick 移动到 tileItem 指令的 link 函数并删除范围:{}它将开始工作。并将 <button ng-click="mytileItemCtrl.btnOKClick()">OK</button> 更改为 <button ng-click="btnOKClick()">OK</button>

一切正常。由于 my-tile-item 指令有自己的独立范围和自己的控制器并不意味着,指令范围将应用于该元素。当指令有自己的 templatetranscluded content 时,指令的作用域会随元素一起编译。所以在 my-title-item 指令中你没有它的 template,这就是为什么指令没有将指令范围应用到它所托管的元素上的原因。

要解决您的问题,您可以在从 my-title-item 指令生成内部模板后使您的 myTileItemCtrl 作用域在元素上可用。然后您可以考虑将 item 作为范围绑定从 my-tile 指令传递到 my-title-item

<script type="text/ng-template" id="myTile.html">
    <div ng-repeat="tileItem in myTileCtrl.tiles" class="my-tile">
       <my-tile-item item="tileItem"></my-tile-item>
    </div>
</script>

我的项目指令

function myTileItem() {
    return {
        restrict: 'AE',
        scope: {
          item: '<'
        },
        template: `
          <div>{{item.id}}</div>
          <button ng-click="myTileItemCtrl.btnOKClick()">OK</button>
        `,
        //...
    }
}

Forked Codepen

通过上述模板结构,您还实现了 Smart and Dumb Component Pattern 父级几乎负责主要责任,而子级仅接受绑定并将其呈现在视图中。

你有一些问题。

我已经更改了你的 codepen,现在可以使用了:https://codepen.io/anon/pen/jLxNvE

第一个错误的解决方法可能是删除 item 指令中的隔离范围,只需删除 item 指令的块 scope。 通过这种方式,您的 item 指令将访问父级的范围,并且可以覆盖该范围添加新属性(作为您的函数)。

但这是错误的解决方案。

遵循最佳方法而不删除项目指令中的隔离范围

您没有为项目指令定义模板。您应该为您想要实现的目标添加一个模板,因为如果您隔离范围,那么您的控制器将只能在该指令的模板中访问,而不会看到父级的范围。没有对应的模板,那里调用不了那个函数

那么在这些情况下最好的办法是你应该在项目指令定义中提供一个范围参数,它实际上是项目(我用双向数据绑定做到了,但我不知道你是什么尝试做,所以根据您的要求更改绑定)。

这样就万事大吉了