javascript - Angular : Accessing parent scope in a transcluded directive that contains nested ng-repeat

标签 javascript angularjs angularjs-directive transclusion

我正在研究一个基本指令,该指令创建适合 Bootstrap 的 div 网格。您给它一个项目集合,并可以选择指定它可以包含的列数。它已被嵌入,因此您可以定义为每个项目显示的模板。

我将集合分成多行,然后嵌套重复器,其中第一个创建每一行,第二个创建每一列(然后嵌入该项目的内容)。它在这个简单的场景中运行良好。

 .directive('grid', [function() {
    return {
            restrict: 'AE',
            template: '<div class="row" ng-repeat="row in rows"><div ng-repeat="item in row" ng-class="{\'col-md-{{columnSpan}}\': true, \'active\': isSelected(item) }"><div class="thumbnail" ng-transclude=""></div></div></div>',
            transclude: true,
            scope: {
                items: '=grid',
                columns: '@',
                columnSpan: '@'
            },
            controller: [
                '$scope', function($scope) {
                }
            ],
            link: function($scope, $el, $attrs) {
                $attrs.$observe('columns', function(val) {
                    $scope.columns = val || 4;
                });

                $attrs.$observe('columnSpan', function(val) {
                    $scope.columnSpan = val || 12 / $scope.columns;
                });

                $scope.$watchCollection('items', function(items) {
                    $scope.rows = $scope.rows || [];
                    $scope.rows.length = 0;

                    if (!items) return;

                    var numRows = Math.floor(items.length / $scope.columns);
                    numRows = items.length % $scope.columns !== 0 ? numRows + 1 : numRows;

                    for (var i = 0; i < numRows; i++) {
                        var row = items.slice(i * $scope.columns, (i + 1) * $scope.columns);
                        $scope.rows.push(row);
                    }

                });
            }
    };
  }]);

问题出在被嵌入的内容中,我有时需要调用一个函数或从父范围访问一个项目。例如,假设我想格式化显示名称,或添加点击处理程序。

<!-- addHello is defined on the controller scope. this doesn't work -->
<div grid="items" columns="3">
  {{addHello(item) || 'Undefined'}} (name is {{item.name}})
</div>

因为这会创建多个嵌入的作用域,所以我必须通过链接 $parent 来取消嵌套作用域,直到我最终找到它。

<!-- works, but ಠ_ಠ -->
<div grid="items" columns="3">
  {{$parent.$parent.$parent.$parent.addHello(item) || 'Undefined'}} (name is {{item.name}})
</div>

这也有效,但它很尴尬并且违反了得墨忒耳法则,这很重要,因为如果我将来更改它在内部的工作方式,它可能会破坏嵌入的内容。我该如何改进以避免这个问题?

Fully functional plunk .

最佳答案

使用委托(delegate)模式。这个想法是在指令中公开一个可定制的函数,并让真正的 Action 被插入。 Action 将在嵌入的范围内触发,调用属于父范围的函数。

<div grid="items" columns="3" custom-action="addHello"> //addHello() belongs to the DemoCtrl's scope 
    {{doAction(item) || 'Undefined'}} (name is {{item.name}}) //doAction() belongs to the translcuded scope
</div>

并将指令更新为如下内容:

scope: {
    ...
    customAction: "&"
},
link: function($scope, $el, $attrs) {

    ...

    $scope.doAction = function(item){
        return $scope.customAction(item);
    }
}

DEMO

关于javascript - Angular : Accessing parent scope in a transcluded directive that contains nested ng-repeat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22676369/

相关文章:

javascript - jQuery 在解析 html 时添加了额外的标签

angularjs - "Failed to execute ' postMessage '"错误来自 Froogaloop 通过 AngularJS 指令

javascript - AsyncTestCompleter Browserify Angular2 HTTP 模拟测试

angularjs - 如何在AngularJS的指令测试中触发ng-change

javascript - ng-click 上的确认对话框 - AngularJS

javascript - 具有内容类型文本/计划的 ionic native HTTP 调用?

javascript - 如何将用户选择的酒店房间乘以入住天数?

javascript - 无法加载显示Json数据

javascript - Angular 指令中的数据困惑

javascript - 当我第二次打开特定页面时,导航栏消失