嵌套指令和父级作用域

5
我有一个问题,可以在 http://jsfiddle.net/miketheanimal/2CcYp/13/ 中看到。这是我将问题最小化后的版本。
我有一个控制器“main”,一个指令“outer”和一个不会转移的指令“inner”。每个指令都有一个隔离作用域和控制器。主要和指令控制器设置$ scope._name = '...',所以我可以区分它们。
var module = angular.module('miketa', []);
function main ($scope) {
    $scope._name = 'main' ;
} ;
module.directive('outer', function() {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: {},
        template: '<div><div ng-transclude></div></div>',
        controller: [ '$scope', function($scope) {
            $scope._name = 'outer' ;
            document.getElementById('opn').innerHTML = $scope.$parent._name ;
        }]}});
module.directive('inner', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {},
        template: '<div></div>',
        controller: [ '$scope', function($scope) {
            $scope._name = 'inner' ;
            document.getElementById('ipn').innerHTML = $scope.$parent._name ;
        }]}});

HTML将它们嵌套为main -> outer -> inner。指令中的控制器函数将它们父级作用域名称(即$ scope.$ parent._name)复制到呈现的HTML中(对于直接操作DOM,我很抱歉,这是显示名称的最简单方法!)。

我期望outer显示来自控制器的名称(即“main”),它确实如此,而我希望inner显示来自outer的名称(即“outer”),但它没有,而是也显示“main”。

实际上,问题表现在实际代码上,我想在innerouter作用域之间进行绑定,但是inner最终绑定到了main作用域。


我认为这很合乎逻辑,你的外部作用域是隔离的,那么你怎么能继承它呢? - Thomas Pons
是的,作用域是隔离的,因此它们不会原型继承,但它们确实有父级作用域($scope.$parent 部分),而且这些似乎不按我预期的方式工作(内部->外部->主要)。正如我在最后一段中所指出的那样,当我尝试在innerouter的作用域之间进行绑定时(即,在内部*scope: {innervar:'=outervar'}*中),这就成为了一个问题。 - Mike Richardson
啊,ng-transclude将ng-scope设置为false! - Thomas Pons
1个回答

9
实际上这不是一个错误,而是期望的行为。在 $compile 服务文档中有如下说明:

在典型的设置中,小部件创建了一个隔离作用域,但插入不是孩子,而是隔离作用域的同级。这使得小部件可以拥有私有状态,并且插入可以绑定到父(前隔离)作用域。

另请参见:如果指令具有隔离作用域,则为什么ng-transclude的作用域不是其指令作用域的子级? 如果您真的需要让它工作,请忘记 ng-transclude 并执行以下操作:
var module = angular.module('miketa', []);

function main($scope) {
    $scope._name = 'main';
};
module.directive('outer', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {},
        template: '<div><inner></inner></div>',
        controller: ['$scope', function ($scope) {
            $scope._name = 'outer';
            document.getElementById('opn').innerHTML = $scope.$parent._name;
        }]
    }
});
module.directive('inner', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {},
        template: '<div></div>',
        controller: ['$scope', function ($scope) {
            $scope._name = 'inner';
            document.getElementById('ipn').innerHTML = $scope.$parent._name;
        }]
    }
});

瞧!它可以运行了。


我曾怀疑transclude是否与此有关,我找到了一些类似但不完全相关的帖子。但是你的更改使outer变得无意义,我可以将其合并到inner中。我试图做的是有一个指令outer,它可以包装不同的内容(即,包装inner1inner2等)。我能否以任何方式实现这一点? - Mike Richardson
没有任何ng-transclude隔离范围,您必须接受这一点!这是AngularJS中转换逻辑,如果您阅读链接线程和文档。 - Thomas Pons
指令 API 是 AngularJS 最强大的部分,但也非常难!无论如何,也许你需要接受或删除这个问题,我不知道。 - Thomas Pons

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接