gpt4 book ai didi

javascript - AngularJS:在包含带有 templateurl 的指令的 html 上使用 $compile

转载 作者:数据小太阳 更新时间:2023-10-29 04:54:22 25 4
gpt4 key购买 nike

我有一个遗留应用程序,它通过 jQuery 将一些内容插入到 DOM 中。我希望代码库的遗留部分负责编译插入到 DOM 中的 html。

我可以使用 $compile 让它编译初始 html,但是任何由指令的模板或 templateUrl 添加的 DOM 元素都不会被编译,除非我调用 $scope.$apply( ) 来自指令本身。

我在这里做错了什么?

fiddle 链接: 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,则此更新的 fiddle 会显示相同的失败行为:

http://jsfiddle.net/trz80n9y/3/

最佳答案

您可能已经意识到,您需要调用 $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 开始对每个范围进行摘要。您只需要消化链接的那个范围,因此消化那个范围就足够了(而且速度更快,对于任何具有大量范围的合理大小的应用程序)。

Forked fiddle

更新:Angular 可以编译字符串和分离的 DOM 节点

我刚刚检查过,OP 实际上是正确的,假设 Angular 可以很好地编译 HTML 字符串或分离的 DOM 节点。但是您需要做的是确保将编译后的 node 实际附加到 DOM,而不仅仅是 HTML。这是因为 Angular 在 DOM 节点* 上将诸如作用域和绑定(bind)信息之类的东西存储为 jQuery/jQueryLite 数据。因此,您需要将额外的信息附加到整个节点,以便 $digest() 能够正常工作。

因此,进行这项工作的另一种方法是将 OP 代码的相同部分更改为:

target.appendChild($compile(html)($scope)[0]);
$scope.$digest()

* 从技术上讲,它存储在内部 jQuery 数据缓存中,缓存键存储在 DOM 节点本身。

关于javascript - AngularJS:在包含带有 templateurl 的指令的 html 上使用 $compile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27008280/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com