演示:http://plnkr.co/edit/TiH96FCgOGnXV0suFyJA?p=preview
我有一个名为myDirective的ng-directive,在指令模板中我有一个使用ng-repeat打印的li标签列表。我想声明li标签的内容作为myDirective声明的一部分,并使用transclude打印所需的text / html内容。这样我可以很好地分离关注点,这样我的指令就不需要知道源项的结构了,调用者负责布局li的内容。
如下所示:
<my-directive source="vm.source">{{label}} and {{id}}</my-directive>
甚至
<my-directive source="vm.source"><a href="#{{id}}">{{label}}</a></my-directive>
ngRepeat的模板(在myDirective中)看起来像
template: '<ul><li ng-repeat="item in source" ng-transclude></li></ul>',
但我无法在hg-repeat内部进行转换。我使用的是角度1.2.19的最新版本。确切地说,trasnclusion工作但不是我在指令级传递的表达式。
请帮忙,谢谢堆!
我无法想出一个更好的问题标题。欢迎你做得更好。
更新:我选择了@pixelbits的答案,因为这就是我的要求。但实际上我使用了@Norguard的方法,因为它更有棱角分明。
答案 0 :(得分:4)
已转换的内容是根据父作用域的子作用域编译的(也称为转换作用域,但这与您的指令的独立作用域不同)。话虽这么说,您可以在父HTML中指定模板(尽管它在角度的正常用例之外)并且根据指令的隔离范围手动编译它。
<强> HTML 强>
<body ng-app="myApp">
<div ng-controller="myController as vm">
<my-directive source="vm.source">
<span>{{item.label}} and {{item.id}}</span>
</my-directive>
</div>
</body>
请注意,my-directive的内部HTML引用了&#39; item&#39;必须在指令的范围内定义。
指令
function directive($compile) {
return {
restrict: 'E',
scope: {
source: '='
},
compile: function(element, attr) {
// in the compile phase, remove the contents
// of element so that it is not compiled by angular.
// We will be manually compiling it in the link function.
var template = angular.element('<ul><li ng-repeat="item in source">' + element.html() + '</li></ul>');
element.empty();
// link function
return function(scope, element, attr) {
// append the template
element.append(template);
// compile and link the template against the isolated scope.
$compile(template)(scope);
}
}
};
}
答案 1 :(得分:2)
杰夫,你的抄送有点倒退。
或者,与你的想法相比,转换工作的方式有点落后。
如果你有一个transcluding指令,并且你把内容放在其中,那么内容是从transclude指令的父节点读取的,而不是指令本身。
对于您的示例,假设:
<div ng-controller="parentController as parent">
<transcluding-directive>
{{ key }} {{ val }}
</transcluding-directive>
</div>
这里有两个问题。
第一个问题是ng-transclude是它所转换内容的兄弟。
他们都会使用parent
作为父母范围
被抄送的内容不会从转录指令内部读取数据
这又是关注点,事物的分离;如果transcluding指令具有与您要转录的内容相同的属性名称,那将覆盖被抄送的内容,并导致各种奇怪的行为,因此他们是兄弟姐妹。
出于所有意图和目的,在幕后,它可能表现如下:
<transcluding-directive></transcluding-directive>
<div>{{ transcludedContent }}</div>
然后,内容将被提取,并附加到transcludingDirective.querySelector("[ng-transclude"])
找到的节点。
这真的不是它的确切运作方式,但它是你得到的结果(缺少你在指令中自己编译/转录例程)。
当您知道第一个错误时,第二个错误更明显:
{{标签}}和vm
的{{id}}是vm
&#39; $scope
个对象的属性。
它们不存在于$scope
,因此undefined
,这就是您从模板中获取'' + 'and' + ''
的原因。
您正在为传递给指令的每个项目创建<li>
,但您要为每个项目插入undefined
和undefined
。
您编写的指令应该是一个专门的指令(知道如何构建那种确切类型的指令的指令),
<specific-list-maker items="vm.list"></specific-list-maker>
或一般指令,您将列表提供给
<generic-drawer>
<ul><li ng-repeat="item in vm.list">{{item.label}} {{item.id}}</li></ul>
</generic-drawer>
...它甚至可能是一个特定的指令,它知道如何在其模板中提供更多通用指令......
<specific-list items="vm.list"></specific-list>
<!-- specific-list.html -->
<generic-drawer>
<generic-toggle ng-repeat="item in items">{{ item.label }} {{ item.id }}</generic-toggle>
</generic-drawer>
这是Angular(和Polymer,以及将来的Web Components本身)非常适合的组合。
作为我一直在研究的项目中的一个简单示例,我有过滤掉的元素,如下所示:
<page-type-a></page-type-a>
<!-- page-type-a.html -->
<card-collection cards="page.items"></card-collection>
<!-- card-collection.html -->
<header ><!-- ... header stuff --></header>
<card ng-repeat="card in cards"></card>
<!-- card.html -->
<header><h1>{{ title }}</h1></header>
<blockquote>{{ content }}</blockquote>
<cite>{{ author }}</cite>
<page-type-b></page-type-b>
<!-- page-type-b.html -->
<card-collection cards="page.items"></card-collection>
每个组件只做自己的工作。
还有其他方法可以让它发挥作用(输入&#34;键&#34;属性和&#34;值&#34;属性,并从列表中的每个项目中功能性地提取值在将ng-repeat
实例链接到transcluding-directive的内部模板之前,为您的$scope
......或者准备好已转换内容中的值,编写自己的内部列表,在将它插入DOM之前......)...但是这样做,在这种情况下就像听起来一样疯狂。