示例:http://jsfiddle.net/avowkind/PS8UT/
我希望嵌套子指令从其包装父指令(如果存在)获取其数据,否则从外部控制器获取数据。
<div ng-controller="MyCtrl">
<parent index="1">
<child></child>
</parent>
<parent index="2">
<child></child>
</parent>
<h1>No Parent</h1>
<child></child>
</div>
<hr>
期望的输出
Parent 1
Child of parent 1
Parent 2
Child of parent 2
No Parent
Child of parent 0
目前我的子对象只看到外部控制器值:
实际输出
Parent 1
Child of parent 0
Parent 2
Child of parent 0
No Parent
Child of parent 0
这是简单的版本;实际上,外部指令从由嵌套子级格式化的服务器获取数据,因此所传达的是复杂对象而不是简单的字符串。此外,子指令是一个可视化,它将在不同的数据集上工作,因此外部父指令并不总是相同的类型。
更一般地说,我试图在这里获得的模式是使用单独的指令来填充模型并查看它。 所以更现实的用法是
<temperature-for city="Auckland">
<plot/>
<analysis/>
</temperature-for>
<humidity-for city="Hamilton">
<plot/>
<analysis/>
</temperature-for>
<test-data>
<plot/>
</test-data>
我个人使用的一种不同方法是将绘图和分析指令定义为隔离范围,然后双向绑定所需的输入。
这样,指令就是完全独立的组件,具有显式定义的接口。我亲自做了这样的绘图指令:
<plot data="countries['Auckland'].plot.data" options="countries['Auckland'].plot.options" legend="external" zoom="xy"></plot>
Scope would look like:
scope: {
data: '=',
options: '=',
zoom: '@?', // '?' indicates optional
legend: '@?',
}
这样就不会混淆此组件工作所需的数据,并且可以在指令中为所需的输入属性编写文档。
总而言之,这是一种模式,它适用于 AngularJS 中的大部分用例,即只要有可重用性的情况。
编辑:只是想补充一点:查看您的 HTML,绝对没有指示这些指令使用什么,它们可能依赖于任何东西(例如,它们是否从服务中获取所有数据?或者它们是否依赖于父范围?如果是这样,范围是什么?
有几种不同的方法可以做到这一点,但假设你真的想在这里使用父作用域,这是一个配合你的小提琴的解决方案。
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.index = 0;
}
myApp.directive('parent', function () {
return {
transclude: true,
scope: {
index: '='
},
restrict: 'EA',
template: '<h2>Parent {{ index }}</h2>',
compile: function(tE, tA, transcludeFn) {
return function (scope, elem, attrs) {
elem.append(transcludeFn(scope)[1]);
};
}
}
});
myApp.directive('child', function () {
return {
restrict: 'EA',
scope: false,
template: '<p>Child of parent {{ index }}</p>'
}
});
你可以在这里看到你的小提琴的叉子。
这个想法是,通过摆脱ngTranscludeDirective并手动创建嵌入,您可以将嵌入与您选择的范围链接起来。然后,您可以将结果附加到指令编译产生的元素中所需的任何位置。
另一个要点是确保子指令不会创建作用域(根本不创建隔离作用域、已包含作用域还是新作用域)。
我认为这会给你你想要的结果。
注意:请仔细研究您的示波器,因为调整这些行为可能会产生意想不到的结果。
例如,如果将链接函数添加到子指令,并且它将索引设置为 5:
link: function(scope) {
scope.index = 5;
}
这不会影响嵌套在父项中的子项的scope.items
。但是,它会影响外部父范围(在本例中为 MyCtrl 的范围)。任何不在父指令内的指令都会不断更改 MyCtrl 索引。
但是,如果在子链接函数中将新属性添加到范围:
link: function(scope) {
scope.somethingElse = foo;
}
无论是否嵌套在父指令中,scope.somethingElse
都将在父作用域中可用。
根据父指令范围对其进行排除和细粒度处理,不能使用 ng-transclude
指令:http://jsfiddle.net/PS8UT/2/
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.index = 0;
}
myApp.directive('parent', function ($compile) {
return {
scope: {
index: '@'
},
restrict: 'EA',
transclude: true,
template: '<h2>Parent {{ index }}</h2>',
link: function (scope, elem, attrs, ctrl, transclude) {
transclude(scope, function(clone, s){
elem.append($compile(clone)(s)); // basically you need to reassign the inner child scope to your current isolated scope
});
}
}
});
myApp.directive('child', function () {
return {
//scope: true, // no need to create another scope since you want to use the parent
// scope: { }, // no index printed
restrict: 'EA',
template: '<p>Child of parent {{ index }}</p>'
}
});
通常,当您处理模板和隐含时,需要父母的遗产是一种痛苦。 ng-transclude
不会使用直接父作用域作为父作用域,它通常使用控制器作用域。在角度文档$compile文档中有说明:
隐含 编译元素的内容并使其可用于 命令。 通常与ngTransclude一起使用。优点 嵌入是链接函数接收嵌入 预绑定到正确范围的函数。在典型设置中 该小组件创建一个隔离范围,但嵌入不是 子级,但隔离范围的同级。这使得 具有私有状态的小部件和要绑定到的嵌入 父(预隔离)范围。