AngularJS:使用$上的HTML编译包含与templateurl指令 [英] AngularJS: Using $compile on html that contains directives with templateurl

查看:148
本文介绍了AngularJS:使用$上的HTML编译包含与templateurl指令的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有了插入通过jQuery的DOM一些内容的遗留应用程序。我想codeBase的遗留部分负责编译它插入到DOM的HTML。

I have a legacy application that has some content inserted into the DOM via jQuery. I would like the legacy parts of the codebase to be responsible for compiling the html that it inserts into the DOM.

我可以得到它使用 $编译编译最初的HTML,而是由一个指令的模板或templateUrl添加任何DOM元素不会被编译,除非我称之为 $范围。$从指令本身内申请()

I can get it to compile the initial html using $compile, but any DOM elements added by a directive's template or templateUrl are not compiled, unless I call $scope.$apply() from within the directive itself.

我在做什么错在这里?

链接拨弄: http://jsfiddle.net/f3dkp291/15/

Link to 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:

So, I should have been compiling dom nodes, not an HTML string. However, this updated fiddle shows the same failing behavior if the directive contains a templateUrl:

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

推荐答案

正如你可能已经意识到,需要调用 $范围。$适用()为它更新在 {{}绑定} 从范围值。

As you probably realised, you need to call $scope.$apply() for it to update the {{bindings}} from the scope values.

但是,你不能这样做,你的异步函数中的原因是你对编译现有范围的HTML #target ,但随后试图只是追加的HTML。这是行不通的,因为你需要有在DOM编译节点,无论是通过附加使用整个编译节点jQuery的 .append()或相似,或通过设置DOM的的innerHTML ,然后再编译那就是在DOM节点。之后,你可以调用 $适用的范围,因为该指令被编译并在DOM,它将被正确更新。

But the reason you couldn't do it inside your async function was that you were compiling the HTML against the existing scope for #target, but then trying to append just the HTML. That won't work, because you need to have the compiled node in the DOM, either by appending the entire compiled node using jQuery's .append() or similar, or by setting the DOM innerHTML first, then compiling the node that is in the DOM. After that, you can call $apply on that scope and because the directive is compiled and in the DOM, it will be updated correctly.

在换句话说,如下更改异步code。

In other words, change your async code as follows.

而不是:

target.innerHTML = $compile(html)($scope)[0].outerHTML
$scope.$apply()

将其更改为:

target.innerHTML = html;
$compile(target)($scope);
$scope.$digest();

请注意,我做了一个 $消化()而不是 $的适用()。这是因为 $适用()做了摘要的每一个范围,从 $ rootScope 开始。你只需要消化一个范围您免受联系在一起,因此它是足够了(快,任何合理大小的应用程序有很多作用域)只是消化的那一个。

Note that I did a $digest() instead of $apply(). This is because $apply() does a digest of every single scope, starting from the $rootScope. You only need to digest that one scope you linked against, so it is sufficient (and faster, for any reasonably sized app with lots of scopes) to just digest that one.

叉形小提琴

我只是检查,而OP是假设角可以编译HTML字符串或分离DOM节点就好实际上是正确的。但你需要做的是确保你真正追加编制的节点应用于DOM,而不仅仅是HTML。这是因为角店之类的东西的范围和为DOM节点上的jQuery / jQueryLite数据绑定信息 * 。因此,你需要添加整个节点,与额外的信息,使 $消化()将工作。

I just checked, and the OP was actually correct in assuming that Angular can compile strings of HTML or detached DOM nodes just fine. But what you do need to do is make sure you actually append the compiled node to the DOM, not just the HTML. This is because Angular stores things like the scope and the binding information as jQuery/jQueryLite data on the DOM node*. Thus you need to append the whole node, with that extra information, so that the $digest() will work.

所以具有该工作的另一种方法是改变OP的code的相同部分如上述为:

So an alternative way of having this work is to change the same portion of the OP's code as above to:

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

<子> *从技术上讲,它被存储在内部的jQuery数据高速缓存,与缓存键所存储的DOM节点本身上。

这篇关于AngularJS:使用$上的HTML编译包含与templateurl指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆