问题 AngularJS:ng-controller on指令不适用于指令中的transcluded元素


这里 是我的剧本:

angular.module('MyApp',[])
.directive('mySalutation',function(){
    return {
        restrict:'E',
        scope:true,
        replace:true,
        transclude:true,
        template:'<div>Hello<div ng-transclude></div></div>',
        link:function($scope,$element,$attrs){
        }
    };
})
.controller('SalutationController',['$scope',function($scope){
    $scope.target = "StackOverflow";
}])

和HTML:

<body ng-app="MyApp">
    <my-salutation ng-controller="SalutationController">
        <strong>{{target}}</strong>        
    </my-salutation>
</body>

问题是,什么时候 SalutationController 适用于 my-salutation 指示, $scope.target  不可见 换了元素。但是如果我放了 ng-controller 上 <body> 或者 <strong> 元素,它的工作原理。如 文档 说, ng-controller 创造新的范围。

  • 谁可以解释,在这种情况下,指令的范围和范围如何相互干扰?

  • 如何将控制器置于指令上?任何提示将不胜感激。


7174
2018-03-22 08:48


起源

这有必要吗?指令可以采取 controller 对象中的参数,除了 link 参数。 - jedd.ahyoung
@ jedd.ahyoung是的,您可以在指令上添加控制器选项,但在这种情况下,您将为所有指令实例使用相同的控制器。如果我不想让任何控制器用于我的指令,或者我需要另一个控制器怎么办?! - Engineer


答案:


1)问题是 ng-transclude的范围是 兄弟 你的指令的范围。当你把它 ng-controller 到父元素,创建范围 ng-controller 是你的指令和。的父范围 ng-transclude。由于范围继承,transcluded元素能够绑定 {{target}} 正确。

2)您可以使用自定义转换来自己绑定范围

.directive('mySalutation',function(){
    return {
        restrict:'E',
        scope:true,
        replace:true,
        transclude:true,
        template:'<div>Hello<div class="transclude"></div></div>',
        compile: function (element, attr, linker) {
            return function (scope, element, attr) {
                linker(scope, function(clone){
                       element.find(".transclude").append(clone); // add to DOM
                });

            };
        }
    };
})

DEMO

或者在链接函数中使用transclude函数:

.directive('mySalutation',function(){
    return {
        restrict:'E',
        scope:true,
        replace:true,
        transclude:true,
        template:'<div>Hello<div class="transclude"></div></div>',
        link: function (scope, element, attr,controller, linker) {
           linker(scope, function(clone){
                  element.find(".transclude").append(clone); // add to DOM
           });
        }
    };
})

DEMO


9
2018-03-22 09:11



Doc说:“注意:不推荐使用传递给compile函数的transclude函数,因为它不知道正确的外部作用域。请使用传递给链接函数的transclude函数。”。这是Angular 1.2中的新功能 这个帖子。 - kamituel
@kamituel:谢谢,我不知道它已经改变了。我已经更新了答案(想法是一样的) - Khanh TO
如果我正确地理解了你的第一点,那就意味着如果我不为指令创建新的范围,那就是 scope 被设定为 false,然后代码应该工作。为什么它在那种情况下不起作用? - Engineer
@Engineer:我调试的时候。我注意到没有区别 true, false。在这两种情况下,指令范围都是控制器范围(相同的$ id)。我认为如果已经存在一个范围,则角度不会创建范围 scope:true - Khanh TO
请注意,find()仅支持标记名称,因此您可能需要执行angular.element(element [0] .querySelector('。classname'))。append(clone)。此外,如果您使用的是隔离范围,则可能需要执行链接器(范围。$ parent,...) - devdigital


要使指令和控制器具有相同的作用域,您可以手动调用transcludeFn:

angular.module('MyApp',[])
.directive('mySalutation',function(){
    return {
        restrict:'E',
        scope:true,
        replace:true,
        transclude:true,
        template:'<div>Hello<div class="trans"></div></div>',
        link:function(scope, tElement, iAttrs, controller, transcludeFn){
                console.log(scope.$id);
                transcludeFn(scope, function cloneConnectFn(cElement) {
                    tElement.after(cElement);
                }); 
        }
    };
})
.controller('SalutationController',['$scope',function($scope){
    console.log($scope.$id);
    $scope.target = "StackOverflow";
}]);

普拉克

您可以看到每次都会注销“003”,并且您的代码可以通过此次调整按预期工作。


2
2018-03-22 09:16