AngularJS - 从加载的内容中注入可信代码

时间:2014-04-29 14:58:22

标签: javascript jquery angularjs lazy-loading

我在Angular中连接了一个懒惰的加载器。它会提取完整模板并从该完整模板中提取关键信息,以便填充部分模板。此完整页面模板具有脚本标记,可加载并随后向现有应用注册。所有这一切都很好。我的问题是我想在这种方法中删除jQuery的唯一用途。

根本问题是something.js内部的JS在使用$element.html()时没有执行,但在使用$.html()时它确实执行,尽管脚本标记放在两种方法中的DOM。

工作代码,包括延迟加载器和延迟加载JS的后引导程序注册:

$http.get("/path/to/file.html").success(function(response) {
  // response is a full HTML page including <doctype>
  var partial = getOnlyWhatWeNeed(response);

  // partial is now something like: '<script type="text/javascript" src="/path/to/something.js"></script><div ng-controller="somethingCtrl">{{something}}</div>'

  // i'd like the following to not rely on full jQuery.
  $("#stage").html(partial);
  $("#stage").html($compile(partial)($scope)); // it is necessary to do it once before compile so that the <script> tags get dropped in and executed prior to compilation.
});

我尝试过似乎合乎逻辑的翻译:

$element.html($compile(partial)($scope));

并且正确创建了DOM,但加载的<script>标记内的JS实际上并未执行。我的研究表明这是一个$sce问题,所以我尝试了:

$element.html($compile($sce.trustAsHtml(partial)($scope));

但我得到了相同的结果。 DOM很好,但JS实际上并没有执行,所以我得到了未定义的控制器问题。

我尝试过使用$sce.JS$sce.RESOURCE_URL,但文档并没有详细说明,所以我不确定我是否知道我尝试的是否是偶数右。

我也试过$element[0].innerHTML,但我得到与$element.html()相同的结果。

抢先免责声明:我可以信任传入的HTML / JS。我知道这是不可取的。这不是我的宝贝,它比我解释的要复杂得多,所以请尽量保持主题,以便其他人在这个位置上可能没有像我这样艰难的时间:)

$http.get发生在提供程序中,$element.html发生在指令中。我巩固了它们以消除问题中的噪音。

1 个答案:

答案 0 :(得分:0)

Jquery会在调用html()时找到任何脚本标记并对其进行评估(直接评估或将其附加到链接脚本的头部),请参阅this answer。我假设angular的jquery lite不会这样做。您需要有效地复制jquery正在执行的操作,并在要附加的html中查找脚本标记。

这样的东西(虽然我没有测试过):

$http.get("/path/to/file.html").success(function(response) {
  // response is a full HTML page including <doctype>
  var partial = getOnlyWhatWeNeed(response);

  // partial is now something like: '<script type="text/javascript" src="/path/to/something.js"></script><div ng-controller="somethingCtrl">{{something}}</div>'

  var d = document.createElement('div');
  d.innerHTML = partial;
  var scripts = d.getElementsByTagName('script');

  for (var i = 0; i < scripts.length; i++) {
      document.head.appendChild(scripts[0]);
  }

  $("#stage").html($compile(partial)($scope)); // it is necessary to do it once before compile so that the <script> tags get dropped in and executed prior to compilation.
});

这远非理想的解决方案,因为它无法保证何时加载内容并且不能真正处理脚本之间的依赖关系。如果您可以控制模板,那么从中删除脚本并单独加载它们会更简单。