好吧,这看起来有点深奥,但我试图用我写的指令来解决一个特定的问题:https://github.com/michaelbromley/angularUtils/issues/37
以下是正在进行的简化版本。
我有一个指令,通过在编译阶段动态地向元素添加ng-repeat
属性来委托ng-repeat,然后编译该元素:
myApp.directive('repeatDelegator', function($compile, $timeout) {
return {
compile: function(element, attrs){
attrs.$set('ngRepeat', attrs.repeatDelegator); //Add ng-repeat to the dom
element.removeAttr('repeat-delegator'); // remove the repeat-delegator to prevent infinite recursion of compilation
var compiled = $compile(element, null);
return function(scope, element, attrs){
compiled(scope);
};
}
}
});
这是指令的调用方式:
<ul>
<li repeat-delegator="item in items">{{item}}</li>
</ul>
这很好用 - 请参阅此处的第一个示例:http://plnkr.co/edit/oWd3rGAulsxoeSqffxMU?p=preview
但是,当repeat-delegator
放在任何其他使用翻译的指令中时,它都不起作用。
这是一个基本指令,除了导致转换外什么都不做:
myApp.directive('transcluder', function() {
return {
restrict: 'AE',
transclude: true,
scope: {},
template: '<div ng-transclude></div>'
};
});
因此,当我们在此转换中调用repeat-delegator
指令时,它会失败并且不显示任何内容:
<transcluder>
<ul>
<li repeat-delegator="meal in meals">{{meal}}</li>
</ul>
</transcluder>
第二个例子说明了这一点:http://plnkr.co/edit/oWd3rGAulsxoeSqffxMU?p=preview
我花了几个小时踩过Angular.js源代码,因为这会执行以试图找出它在转换中失败的原因,但我无法深入到它的底部。
在破碎(转换)版本中,当我看到正在编译的ngRepeat时,$ scope似乎是正确的(它是主控制器$ scope的子$ scope,因为转换会导致一个新的子$ scope到被创造)。您可以在控制台中编写“scope.items”并查看项目列表。
我猜这样的事情正在发生:
$template
var中,以便以后插入到DOM中。ng-repeat
针对<li>..</li>
节点的 clone 进行编译,而该节点实际上从未实际连接回DOM?我不确定。这是一个非常棘手的问题,任何帮助都会非常感激!
答案 0 :(得分:3)
好的,在开发工具中使用Angular.js源代码的一天后,我发现这里出了什么问题,我上面的猜测基本上是正确的。
麻烦的是,repeat-delegator
指令将针对分离的克隆进行编译,因此有效地将ng重复的元素附加到丢失的DOM片段中,该片段永远不会附加到页面主体
解决方案非常简单:将repeat-delegator的委托ng-repeat的编译移动到链接函数中(而不是在编译阶段,最初的位置)。
这样做意味着当ng-repeat被编译时,它是针对正确的DOM节点完成的,该节点现在安全地连接到transcluded指令下面的DOM。
myApp.directive('repeatDelegator', function($compile, $timeout) {
return {
compile: function(element, attrs){
attrs.$set('ngRepeat', attrs.repeatDelegator); //Add ng-repeat to the dom
element.removeAttr(attrs.$attr.repeatDelegator); // remove the repeat-delegator to prevent infinite recursion of compilation
return function(scope, element, attrs){
var compiled = $compile(element);
compiled(scope);
};
}
}
});