【问题标题】:AngularJS : ng-controller on directive does not work on transcluded elements within directiveAngularJS:指令上的 ng-controller 不适用于指令中的嵌入元素
【发布时间】:2014-04-29 19:17:50
【问题描述】:

Here 是我的脚本:

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 放在&lt;body&gt; 或@ 上987654330@ 元素,它有效。正如docs 所说,ng-controller 创建了新的范围。

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

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

【问题讨论】:

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

标签: javascript angularjs angularjs-directive transclusion


【解决方案1】:

1) 问题是ng-transclude 的作用域是你的指令的sibling 作用域。当您将ng-controller 放入父元素时,ng-controller 创建的范围是您的指令和ng-transclude 的父范围。由于作用域继承,被嵌入的元素能够正确绑定{{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

【讨论】:

  • Doc states: "注意:不推荐使用传递给编译函数的 transclude 函数,因为它不知道正确的外部范围。请使用传递给而是链接功能。”。根据 this post,这是 Angular 1.2 中的新功能。
  • @kamituel:谢谢,我不知道它已经改变了。我已经更新了答案(思路一样)
  • 如果我正确理解了您的第一点,这意味着如果我不会为指令创建新范围,即 scope 设置为 false,那么代码应该可以工作。为什么它在这种情况下不起作用?
  • @Engineer:我调试的时候。我注意到truefalse 没有区别。在这两种情况下,指令范围都是控制器范围(相同的 $id)。我认为如果已经有一个范围,即使scope:true
  • 注意 find() 只支持标签名,所以你可能需要做 angular.element(element[0].querySelector('.classname')).append(clone)。此外,如果您使用的是隔离范围,则可能需要执行 linker(scope.$parent, ...)
【解决方案2】:

要使指令和控制器具有相同的范围,您可以手动调用 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";
}]);

plunk

您可以看到“003”每次都被注销,并且您的代码通过这个小调整可以正常工作。

【讨论】:

    猜你喜欢
    • 2017-12-31
    • 2015-08-09
    • 1970-01-01
    • 2012-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 1970-01-01
    相关资源
    最近更新 更多