我正在使用一个包含指令,它本身正在使用一个 Controller ,它应该重新定义内部范围,但事实并非如此。而且无论我使用多少技巧,我似乎都无法完成这件事(让我相信我做错了什么)。
代码简化为一个简单的案例,如下所示:
HTML:
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.1/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<mydirective>
{{foo}}
</mydirective>
</body>
</html>
JavaScript:
angular.module('app', [])
.controller('MainCtrl', function($scope) {
$scope.foo = 'bar';
})
.controller('InDirectiveController', function($scope) {
$scope.foo = 'baz';
})
.directive('mydirective', function() {
return {
restrict: 'EA',
scope: false,
template:'<div ng-controller="InDirectiveController">'+
'{{foo}} <inside></inside>'+
'</div>',
transclude:true,
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone, scope) {
element.find("inside").append(clone);
});
}
};
});
例子在这里
http://jsbin.com/wuqoqalenu/1/edit?html,js,output
我希望输出是“baz baz”,因为我专门使用了 transclude 函数。但是,它实际上是“baz bar”,我不确定如何强制嵌入代码的范围使用我在 Controller 中设置的范围。
最佳答案
在没有 replace:true 的情况下,您基本上会得到指令 HTML 的以下内容(编译前)
<mydirective>
<div ng-controller="InDirectiveController">
{{foo}} <inside></inside>
</div>
<mydirective>
编译时,指令作用域与外部 (MainCtrl) 作用域保持相同,因此嵌入的内容将根据该作用域进行评估。因此第一个 {{foo}} 是“baz”(来自 InDirectiveController),嵌入的内容 {{foo}} 是“bar”(来自 MainCtrl)。
使用 replace:true,编译指令 HTML 变为:
<div ng-controller="InDirectiveController">
{{foo}} <inside></inside>
</div>
当 Angular 编译它时,ng-controller 会创建一个新的作用域,它继承自 MainCtrl 的作用域,它与指令的 DOM 节点相关联,因此它成为指令的作用域。因此,当您执行嵌入时,它现在正在使用 InDirectiveController 的范围,因此您会得到“baz baz”。
更新以解决评论中的问题:
指令并不总是创建新的范围。当你使用
scope: false
指令范围将与“外部范围”相同。因此,当指令的链接函数运行时,它将是“外部范围”。
transclude 函数使用作为第一个参数传递的范围作为被嵌入内容的范围。在您的第一个示例中,此范围是传递给链接函数的范围,在第一种情况下将是“外部范围”。
当您设置 replace: true 时,这仍然不会导致创建新范围。但是,您的模板在其外部元素上使用 ng-controller。 Angular 通过“向下”遍历 DOM 进行编译,并通过向上遍历进行链接。所以它编译指令,然后编译模板,然后链接模板(调用 ngController 的链接函数创建一个新的范围),然后指令的链接函数与指令的模板元素的范围,现在是创建的范围ng-controller(而不是“外部范围”)。
更新:没有 mg-controller 的指令实现
.directive('mydirective', function() {
return {
restrict: 'EA',
scope: true,
controller: function($scope) {
$scope.foo = 'baz';
},
template:'<div>'+
'{{foo}} <inside></inside>'+
'</div>',
transclude:true,
link: function(scope, element, attrs, ctrl, transclude) {
transclude(scope, function(clone, scope) {
element.find("inside").append(clone);
});
}
};
});
关于javascript - 包含指令的指令不使用指令范围,即使特别告知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30408170/