【发布时间】:2013-08-26 02:42:06
【问题描述】:
在我的理解中,$compile 应该能够支持嵌套指令编译/链接,但是我们遇到了一个编译/链接不完整的问题——只有最外层的指令被渲染到 DOM 中,并且只有在两者都出现时才会重现该问题以下条件为真:
- 内部指令模板通过templateUrl加载(例如异步方式)
- 编译是在 Angular 上下文之外触发的。
我写了一个jsfiddler来演示,部分代码如下,完整案例http://jsfiddle.net/pattern/7KjWP/
myApp.directive('plTest', function($compile){
return {
restrict :'A',
scope: {},
replace: true,
template: '<div>plTest rendered </div>',
link: function (scope, element){
$('#button1').on('click', function(){
var ele;
ele = $compile('<div pl-shared />')(scope);
console.log('plTest compile got : '+ ele[0].outerHTML);
// scope.$apply();
element.append(ele);
});
}
};
});
myApp.directive('plShared', function($compile, $timeout){
return {
restrict: 'A',
scope: {},
replace: true,
link: function (scope, element){
// comment out below line to make render success
//$timeout(function(){});
var el = $compile('<div pl-item></div>')(scope);
console.log('plShared compile got:' + el[0].outerHTML);
element.append(el);
}
};
});
myApp.directive('plItem', function($timeout){
return {
restrict: 'A',
scope:{},
template:'<div>plItem rendered <div pl-avatar/></div>',
link: function(scope){
}
};
});
myApp.directive('plAvatar', function(){
return {
restrict: 'A',
scope: {}
, templateUrl: 'avatar.html'
// ,template: 'content of avatar.html <div pl-image></div>'
};
});
有趣的是,我可以通过在 compile() 调用之后的某个地方调用 scope.$apply() 来解决这个问题(第 27 行) 或将 $timeout(function(){}) 调用添加到内部指令之一的链接函数中(第 41 行)。这是缺陷还是设计使然?
【问题讨论】:
-
这就是 2-way 绑定的工作原理,要么你在 Angular 上下文中进行更改,要么你必须自己调用 $apply()。
-
正如@stevuu 解释的那样,您代码中的实际问题是这一行:` $('#button1').on('click',..` - angular 不知道这除非您致电
$scope.$apply(),否则事件已由您的代码处理 -
我知道有必要在角度上下文之外调用 scope.$apply() 以推出 $evalAsyc 和 $watch 检查,但令我困惑的是为什么指令编译与那些支票。猜测可能是模板以异步方式加载,这样 Angular 可能没有机会在所有异步加载完成之前链接所有模板,因此需要 $apply() 显式解决来自 $evalAsyc 队列的那些加载承诺。如果是这样,那么额外的$apply()是合理的,否则不一致有点烦人。
-
顺便说一句,只是从角度源代码中找到, $timeout(function{}) 也会在内部触发 $rootScope.$apply() 调用。默认情况下会触发呼叫。如果我使用 $timeout(function{}, 0, false) 跳过调用。第二个 $timeout 解决方案不起作用。
-
我遇到了同样的问题,通过添加 $apply 也解决了,感谢您提供的信息。但是我仍然感到困惑,因为在我的情况下,HTML 始终是异步加载的,并且问题仅出现在一种情况下——HTML 先前已加载并且在 $compile 和重新插入之前被 .removed。我会认为 $compile 总是递归的,为什么在 $compile 之后需要 $apply?
标签: angularjs