我有一个遗留应用程序,该应用程序通过jQuery将一些内容插入了DOM。我希望代码库的遗留部分负责编译它插入DOM中的html。
我可以使用来编译初始html
$compile
,但是除非我$scope.$apply()
从指令内部调用,否则不会编译指令模板或templateUrl添加的任何DOM元素。
我在这里做错了什么?
链接到小提琴:
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,则此更新的小提琴将显示相同的失败行为:
http://jsfiddle.net/trz80n9y/3/
正如您可能意识到的那样,您需要调用$scope.$apply()
它以{{bindings}}
从范围值更新。
但是您无法在异步函数中执行此操作的原因是,您正在针对的现有范围编译HTML
#target
,然后尝试仅追加HTML。那是行不通的,因为您需要在DOM中拥有已编译的节点,要么通过使用jQuery
.append()
或类似方法附加整个已编译的节点,要么innerHTML
先设置DOM
,然后再编译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节点本身上。
问题内容: 我正在使用Jasmine编写AngularJS的指令测试,并与它们一起使用templateUrl:https : //gist.github.com/tanepiper/62bd10125e8408def5cc 但是,当我运行测试时,我得到了要点中包含的错误: 从我在文档中阅读的内容来看,我认为自己做得正确,但是事实并非如此-我在这里想念的是什么? 谢谢 问题答案: 如果您使用的是ng
问题内容: 在以下情况下如何使用包含。目的是在html(部分)文件中使用标记,而不是在模板中(在指令内)定义标记。 我在这里找到了一个很棒的树指令。( 来源)原文: http //jsfiddle.net/n8dPm/ 我没有在指令中定义模板,而是尝试使用包含在内的内容。我还将Angular更新为1.2.0.rc2。更新时间:http://jsfiddle.net/aZx7B/2/ 低于错误 Ty
问题内容: 我有一个指令,用于最近重构的表单验证样板。在扩展之前,请允许我进一步解释该指令。 指令用法: 以前,我的指令看起来像这样,并且 有效 。 html模板变得一团糟,我想将按钮包装在模板的“内部”,而不是在按钮之后。因此,我将其重构为我认为更好的指令。 因此,我注意到的是element.html()现在检索templateUrl的内容,而不是我指令的内部HTML的内容。在指令被templa
问题内容: 我有一条指令,该指令的行为应有所不同,具体取决于自初始化以来经过的时间: 问题是,当我尝试使用Jasmine进行测试时,我似乎找不到以任何方式触发此超时的方法。已经尝试了和(如果我要注释调用,实际上会引发错误)。但是它仍然没有触发超时的回调执行 测试失败。 找不到我在做什么错。关于如何正确测试这种情况的任何提示? 谢谢。 UPD 经过一番调查,我发现在此特定的测试用例中,在功能上,服务
问题内容: 我有一个已定义的AngularJS指令。我正在尝试与Jasmine进行单元测试。 根据此建议,我的JasmineJavaScript如下所示: 当我在Jasmine spec错误中运行此命令时,出现以下错误: 我想要的只是让templateUrl原样加载- 我不想使用。我相信这可能与使用ngMock而不是ngMockE2E有关。如果是罪魁祸首,如何使用后者而不是前者? 提前致谢! 问题
问题内容: 我有一个递归的Angular指令,该指令使用模板变量并在函数中进行编译。 问题是,我的模板已经变得很长且不受控制,我想将其外部化到一个外部HTML文件中(这也将使其更易于自动缩进)。 您如何将外部模板加载到可以在内部使用的指令中? 我已经看过了,但是那不能让我命名变量并将其传递给函数。 和 问题答案: 您可以使用该服务获取模板。这是一项便捷服务,该服务还将模板缓存在中,因此仅发出一个请