[英]AngularJS: Using $compile on html that contains directives with templateurl
我有一个遗留应用程序,通过jQuery将一些内容插入到DOM中。 我希望代码库的遗留部分负责编译它插入DOM的html。
我可以使用$compile
来编译初始html,但是指令的模板或templateUrl添加的任何DOM元素都不会编译,除非我从指令本身调用$scope.$apply()
。
我在这做错了什么?
链接到小提琴: http://jsfiddle.net/f3dkp291/15/
的index.html
<div ng-app="app">
<debug source='html'></debug>
<div id="target"></div>
</div>
的application.js
angular.module('app', []).directive('debug', function() {
return {
restrict: 'E',
template: "scope {{$id}} loaded from {{source}}",
link: function($scope, el, attrs) {
$scope.source = attrs.source
if( attrs.autoApply ) {
// this works
$scope.$apply()
}
},
scope: true
}
})
// mimic an xhr request
setTimeout(function() {
var html = "<div><debug source='xhr (auto-applied)' auto-apply='1'></debug><br /><debug source='xhr'></debug></div>",
target = document.getElementById('target'),
$injector = angular.injector(['ng','app']),
$compile = $injector.get('$compile'),
$rootScope = $injector.get('$rootScope'),
$scope = angular.element(target).scope();
target.innerHTML = $compile(html)($scope)[0].outerHTML
// these do nothing, and I want to compile the directive's template from here.
$scope.$apply()
$scope.$root.$apply()
angular.injector(['ng','app']).get('$rootScope').$apply()
}, 0)
产量
scope 003 loaded from html
scope 005 loaded from xhr (auto-applied)
scope {{$id}} loaded from {{source}}
更新:解决方案适用于具有模板属性的指令,但不适用于templateUrl
所以,我本来应该编译dom节点,而不是HTML字符串。 但是,如果指令包含templateUrl,则此更新的小提示显示相同的失败行为:
您可能已经意识到,您需要调用$scope.$apply()
来更新范围值中的{{bindings}}
。
但是你无法在异步函数中执行此操作的原因是您正在针对#target
的现有范围编译HTML,但之后尝试仅添加HTML。 这是行不通的,因为你需要在DOM中编译已编译的节点,或者通过使用jQuery的.append()
或类似方法附加整个编译节点,或者首先设置DOM innerHTML
,然后编译其中的节点。 DOM。 之后,您可以在该范围内调用$apply
,因为该指令已编译,并且在DOM中,它将被正确更新。
换句话说,更改您的异步代码如下。
代替:
target.innerHTML = $compile(html)($scope)[0].outerHTML
$scope.$apply()
将其更改为:
target.innerHTML = html;
$compile(target)($scope);
$scope.$digest();
请注意,我做了$digest()
而不是$apply()
。 这是因为$apply()
从$rootScope
开始对每个范围进行摘要。 您只需要消化您链接的一个范围,因此只需消化那个范围就足够了(并且对于任何具有大量范围的合理大小的应用程序来说更快)。
我刚刚检查过,OP实际上是正确的,假设Angular可以编译HTML或分离的DOM节点的字符串就好了。 但您需要做的是确保实际将编译后的节点附加到DOM,而不仅仅是HTML。 这是因为Angular将范围和绑定信息等内容存储为DOM节点*上的jQuery / jQueryLite数据。 因此,您需要使用该额外信息附加整个节点,以便$digest()
可以工作。
因此,另一种方法是将上述OP代码的相同部分更改为:
target.appendChild($compile(html)($scope)[0]);
$scope.$digest()
*从技术上讲,它存储在内部jQuery数据缓存中,缓存密钥存储在DOM节点本身上。
首先将元素附加到目标,然后编译它。
html = angular.element(html);
target = angular.element(target);
target.append(html);
html = $compile(html)($scope)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.