嵌套元素指令无法访问父指令范围

Posted

技术标签:

【中文标题】嵌套元素指令无法访问父指令范围【英文标题】:Nesting element directives can't access parent directive scope 【发布时间】:2013-05-22 11:51:22 【问题描述】:

我已经为此苦苦挣扎了很长一段时间,但我不知道如何解决这个问题。

我正在尝试创建一个网格指令,其中包含用于描述网格的列指令,但列不会是元素,只会将列添加到在网格指令范围内声明的数组中。

我认为解释这个问题的最好方法是查看查看代码:

var myApp = angular.module('myApp', [])

    .controller('myCtrl', function ($scope, $http) 
    )
    .directive('mygrid', function () 
        return 
            restrict: "E",
            scope: true,
            compile: function ($scope) 
                debugger;
                $scope.Data = ;
                $scope.Data.currentPage = 1;
                $scope.Data.rowsPerPage = 10;
                $scope.Data.startPage = 1;
                $scope.Data.endPage = 5;
                $scope.Data.totalRecords = 0;
                $scope.Data.tableData = ;
                $scope.Data.columns = [];
            ,
            replace: true,
            templateUrl: 'mygrid.html',
            transclude: true
        ;
    )
    .directive('column', function () 
        return 
            restrict: "E",
            scope: true,
            controller: function ($scope) 
                debugger;
                $scope.Data.columns.push(
                    name: attrs.name
                );

            
        ;
    );

这里是 HTML 标记:

<body ng-app="myApp">
<div ng-controller="myCtrl">
    <input type="text" ng-model="filterGrid" />
    <mygrid>
        <column name="id">ID</column>
        <column name="name">Name</column>
        <column name="type">Type</column>
        <column name="created">Created</column>
        <column name="updated">Updated</column>
    </mygrid>
</div>

另外可以在jsfiddle中测试实际代码:http://jsfiddle.net/BarrCode/aNU5h/

我尝试使用编译、控制器和链接,但由于某种原因,父网格的列未定义。

我该如何解决这个问题?

编辑: 当我从 mygrid 指令中删除 replace、templateUrl、transclude 时,我可以从 column 指令中获取范围。

谢谢

【问题讨论】:

这有什么成功吗? 是的,在 angularJS 的更高版本中,您可以使用 $scope.$$childHead 获取父指令 【参考方案1】:

在更高版本的 AngularJS 中,我发现 $scope.$$childHead 可以满足我的要求。

它仍然是新的,但它也适用于具有隔离范围的指令。

所以在 Columns 指令中你可以这样做:

$scope.$$childHead.Data.columns.push(
                    name: attrs.name
                );

只需确保在网格编译后执行此命令即可。你可以这样做,但要在编译、链接和控制器之间切换,因为它们中的每一个都有不同的加载优先级。

【讨论】:

【参考方案2】:

我明白你想要做什么,但使用 column 指令可能不是解决问题的最佳方法。

您正在尝试使用可自定义的列定义 grid 指令。每列都有 2 条相关信息:用于访问行数据中的值的键和要显示的标题。

暂时忽略所有与分页相关的内容,这是解决问题的另一种方法。

首先,让我们使用属性来定义列信息,所以我们的 HTML 如下所示:

<body ng-app='app' ng-controller='Main'>
    <grid col-keys='id,name,type'
          col-titles='ID,Name,Type'
          rows='rows'>
    </grid>
</body>

对于 JS,我们显然需要 app 模块:

var app = angular.module('app', []);

这是grid 指令。它使用隔离作用域,但使用= 2-way 绑定从其父作用域获取行数据。请注意链接函数如何从attrs 对象中提取列信息。

模板变得非常简单:循环列标题以定义标题,然后循环rows,并在每一行中循环列键。

app.directive('grid', function() 
    return 
        restrict: 'E',
        scope: 
            rows: '='            
        ,
        link: function(scope, element, attrs) 
            scope.colKeys = attrs.colKeys.split(',');
            scope.colTitles = attrs.colTitles.split(',');
        ,
        replace: true,
        template:
            '<table>' +
            '  <thead>' +
            '    <tr>' +
            '      <th ng-repeat="title in colTitles">title</th>' +
            '    </tr>' +
            '  </thead>' +
            '  <tbody>' +
            '    <tr ng-repeat="row in rows">' +
            '      <td ng-repeat="key in colKeys">row[key]</td>' +
            '    </tr>' +
            '  </tbody>' +
            '</table>'
    ;
);

还有一些示例数据可以开始使用。

app.controller('Main', function($scope) 
    $scope.rows = [
        id: 1, name: 'First', type: 'adjective',
        id: 2, name: 'Secondly', type: 'adverb',
        id: 3, name: 'Three', type: 'noun'
    ];
);

Here it is in fiddle form.

【讨论】:

感谢您的解释,但我真的更愿意使用我的标记方式来解决这个问题,因为如果我想更改列顺序或向我拥有的列添加更多选项,请按照您的方式将它传递给网格中的另一个属性,它最终会看起来很长而且很乱。尝试简化标记方面的所有内容,并在指令方面做所有艰苦的工作。 问题在于你将 JS 值编码到 HTML 中,这与使用 Angular 的目标背道而驰。请注意,我只是在这里使用字符串来简化事情。 colKeyscolTitles 可以通过类似 rows 的隔离范围引用并在父控制器中定义,避免“冗长而混乱”。【参考方案3】:

正如伊姆里所说:

在更高版本的 AngularJS 中,您可以使用 $scope.$$childHead 获取父指令

我没有测试过。

【讨论】:

以上是关于嵌套元素指令无法访问父指令范围的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS指令隔离范围和父范围

如何使用 Angular 中的依赖注入将属性指令实例传递给嵌套组件

在 AngularJS 中从没有隔离范围的指令调用控制器函数

如何从编译器函数指令访问范围?

为啥切换效果不适用于使用角度指令的嵌套 div

如何在模块化的angularjs范围内测试指令?