我想创建一个指令,用于组织按日期分组的显示数据。我还希望能够指定一个显示各行的指令。在一个完美的世界里,它会看起来像这样(但很漂亮)
Friday, Oct 28
[some directive html]
[some directive html]
[some directive html]
Saturday, Oct 29
[some directive html]
Sunday, Oct 30
[some directive html]
[some directive html]
...
这显然不起作用,所以如果你有更好的方法,请告诉我,但我希望能够按照以下方式做点什么:
app.directive('dateOrganized', [function(){
return {
template:
'<div>' +
'<div ng-repeat="organizedDate in organizedDate">' +
'<div>{{organizedDate.date | date}}</div>' +
'<div ng-repeat="item in organizedDate.items">' +
'{{rowDirectiveHtml}}' +
'</div>' +
'</div>' +
'</div>',
scope: {
organizedDates: '=',
rowDirectiveHtml: '='
}
...
};
}])
app.directive('itemRow', [function(){
return {
template: '<div>{{item.data}}</div>',
scope: {
item: '='
}
};
}]);
然后像这样使用它:
<div data-organized organized-dates="stuff" row-directive-html="<div item-row item=\"item\" />" />
我知道这是非常丑陋的(并且不起作用,但我确信我可以通过一些调整来实现它)所以我真的在问,是否有更好的方法来做到这一点?
答案 0 :(得分:12)
这个问题比看起来更复杂,所以让我们把它分解。
您正在构建的是一个接受部分模板的指令 - <div item-row item="item" />
- 和 该模板使用(或与范围相关联)内部模板变量 - item
- 用户未在外部范围中定义;它的含义由您的指令定义,您的用户通过阅读指令的文档来“发现”它。我通常使用带前缀的$
命名这样的“魔术”变量,例如$item
。
第1步
不是通过属性绑定将模板作为HTML-as-string传递,而是将其作为内容传递并转换该内容。 Transcluding允许您将已转换的内容绑定到任意范围:
<foo>
<div>my item is: {{$item}}</div>
</foo>
.directive("foo", function(){
return {
scope: {},
transclude: true,
template: "<h1>I am foo</h1><placeholder></placeholder>",
link: function(scope, element, attrs, ctrls, transclude){
scope.$item = "magic variable";
transclude(scope, function(clonedContent){
element.find("placeholder").replaceWith(clonedContent);
});
}
};
});
以上内容会将模板<div>my item is: {{$item}}</div>
(可以是您指定的任何模板)放置在指令foo
所决定的位置,并将链接到已定义$item
的范围。
第2步
但是你的指令增加的复杂性在于它使用ng-repeat
,它本身接受一个模板,你的指令接收的模板需要用作ng-repeat
的模板。
只使用上述方法,这不起作用,因为在link
运行时,ng-repeat
在您有机会申请之前已经转换了自己的内容。
解决这个问题的一种方法是手动$compile
foo
模板,而不是使用template
属性。在编译之前,我们将有机会在需要的地方放置预期的模板:
.directive("foo", function($compile){
return {
scope: {},
transclude: true,
link: function(scope, element, attrs, ctrls, transclude){
scope.items = [1, 2, 3, 4];
var template = '<h1>I am foo</h1>\
<div ng-repeat="$item in items">\
<placeholder></placeholder>\
</div>';
var templateEl = angular.element(template);
transclude(scope, function(clonedContent){
templateEl.find("placeholder").replaceWith(clonedContent);
$compile(templateEl)(scope, function(clonedTemplate){
element.append(clonedTemplate);
});
});
}
};
});
<强> Demo 强>