【问题标题】:Programmatically compile an Angular template to a HTML string以编程方式将 Angular 模板编译为 HTML 字符串
【发布时间】:2017-04-07 10:55:20
【问题描述】:

在我的 Angular 1.5.11 应用程序中,我尝试以编程方式编译模板并将结果作为 HTML 字符串获取。模板的内容是

<div ng-if="foo">
  <div>foo is {{foo}}, bar is {{bar}}</div>
</div> 

我尝试将其编译为 HTML 字符串:

app.controller('MainCtrl', function($scope, $rootScope, $compile) {

  function compileHtmlTemplate (templateContent, model) {
    var templateScope = $rootScope.$new(true);
    angular.extend(templateScope, model);

    return $compile(templateContent)(templateScope);
  }

  var templateContent = $('#template').html();
  var model = {foo: 'fooValue', bar: 'barValue'};
  var compiledHtml = compileHtmlTemplate(templateContent, model);
  var htmlAsString = $('<div></div>').html(compiledHtml).html();

  $scope.result = htmlAsString;
});

但是,正如您在 Plunker example 中看到的那样,它不起作用。我需要编译模板而不是插值,因为它包含一个ng-if 指令。

【问题讨论】:

  • 想发明轮子?或者你想得到什么?正如您在上一个问题中所评论的那样,您可能想要 $interpolate 而不是 $compile。
  • 编译后需要对值进行$eval
  • @PetrAveryanov $interpolate 不起作用,因为模板包含指令
  • @blackmiaool foo 有一个值,所以 ng-if 评估为真。
  • @estus OP 并没有说这不是一个有用的、有效的问题。只是他们不想进一步解释。这完全是他们的特权。一方面,细节可能具有商业敏感性。此外,在 100k 时,他们已经存在足够长的时间,可以在后台拥有一定程度的经验。

标签: javascript angularjs


【解决方案1】:

Angular 的摘要循环需要完成,然后您才能访问该值。您可以使用$timeout 来实现。

我使用$templateCache 来检索模板,因为这是官方方式,但这只是个人喜好。

var app = angular.module('plunker', ['ngSanitize']);

app.controller('MainCtrl', function($scope, $rootScope, $compile, $timeout, $templateCache) {

  function compileHtmlTemplate (templateContent, model) {
    var templateScope = $rootScope.$new(true);
    angular.extend(templateScope, model);

    var compiled = $compile(templateContent)(templateScope);

    var parent = $("<div>").html(compiled);

    console.log("Won't work! Digest hasn't finished:", parent[0].innerHTML);

    $timeout(function(){ // must wait till Angular has finished digest
      console.log('Will work, digest has now completed:', parent[0].innerHTML);

      $scope.result = parent[0].innerHTML;
    }, 0);
  }

  // either do something with the compiled value within the $timeout, or watch for it
  $scope.$watch('result', function(newValue, oldValue) {
      if (newValue !== undefined) {
        console.log("Do something in the $timeout or here... " + newValue);
      }
  });

  // you can access the template via the template cache if you wanted
  var templateContent = $templateCache.get('template');
  var model = {foo: 'fooValue', bar: 'barValue'};
  var compiledHtml = compileHtmlTemplate(templateContent, model);
});

更新的 Plunker:https://plnkr.co/edit/ajC3Iqkxpi6O9gfieHeR?p=preview

【讨论】:

  • 更新了 Plunk 以将结果与呈现的模板版本进行比较。还添加了 foo: false 注释掉的测试用例
【解决方案2】:

是的,你可以在这里像这样使用 $interpolate

var app = angular.module('plunker', ['ngSanitize']);

app.controller('MainCtrl', function($scope, $rootScope, $compile, $interpolate) {

  function compileHtmlTemplate (templateContent, model) {
    var templateScope = $rootScope.$new(true);
    angular.extend(templateScope, model);

    var tpl = $compile(templateContent)(templateScope);
    console.log(tpl);

    return $interpolate(tpl.html(),model)
  }

  var templateContent = $('#template').html();

  var model = {foo: 'fooValue', bar: 'barValue'};
  var compiledHtml =compileHtmlTemplate(templateContent)(model);
  //console.log(compiledHtml)
  var htmlAsString = $('<div></div>').html(compiledHtml).html();

  $scope.result = htmlAsString;
});

使用模型插值返回编译后的 html,然后使用相同的。

$compile 返回一个不是 html 字符串的元素

https://plnkr.co/edit/TPvOXb5TWHGUunBMFubF?p=preview

【讨论】:

  • 感谢您的回答。我忘了提到模板中有一个指令,所以我需要编译它。在向模板添加 ng-if 指令后,我尝试了您的解决方案,但它不起作用。我已经更新了我的问题和 Plunker 示例以在模板中包含一个指令。
【解决方案3】:

如果你想显示 HTML,你不能简单地使用 {{}},你需要使用 ng-bind-html 或使用 $sanitaze angular 服务

我已经更新了你的 plunker https://plnkr.co/edit/GwM5CEemo961s2CeUsdA?p=preview

var compiledHtml = compileHtmlTemplate(templateContent, model);
var element = angular.element('<div></div>').html(compiledHtml)
$timeout(function() {
  $scope.result = element.html()
})

由于模板中的ngIf compiledHtml 仅返回ngIf 评论,我之前曾与之抗争,我想出的唯一解决方案是在将compiledHtml 附加到新创建的元素时如上所述并在没有指定时间的情况下检索$timeout 中的html,因为它将在附加和$digest 循环之后发生。希望对你有帮助

【讨论】:

    【解决方案4】:

    以下是您的代码的工作版本(大部分更改与以角度方式做事有关)

      var templateContent = $templateCache.get("template");
      //var templateContent = $('#template').html();
      //comment: get html in angular way, not using jquery
    
      var model = {foo: 'fooValue', bar: 'barValue'};
      var templateScope = $rootScope.$new(true);
      templateScope = angular.extend(templateScope, model);
      //angular.extend(templateScope, model);
      //comment: make sure to capture result of angular.extend
    
      var compiledElement = $compile(templateContent)(templateScope);
      //var compiledHtml = $compile(templateContent)(templateScope);
      //comment: result of compilation is not an html but an angular element
    
      var targetElement = angular.element("#result");
      //var htmlAsString = $('<div></div>').html(compiledHtml).html();
      //comment: find the element using angular and not jquery
    
    
      targetElement.append(compiledElement);
      //$scope.result = htmlAsString;
      //comment: don't just assign string, append an angular element
    

    更新plunker link

    html 的一个小改动是

      replaced
      <div>{{result}}</div>
    
      with
      <div id="result"></div>
    

    【讨论】:

      猜你喜欢
      • 2016-02-23
      • 2013-07-31
      • 2016-12-30
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多