以编程方式将Angular模板编译为HTML字符串

时间:2017-04-07 10:55:20

标签: javascript angularjs

在我的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指令。

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

是的,你可以在这里使用$ 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

答案 2 :(得分:0)

如果您想要显示HTML,则无法使用{{}},您需要使用ng-bind-html或使用$sanitaze角度服务

我已经更新了您的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周期后发生。希望有所帮助

答案 3 :(得分:0)

下面是您的代码的工作版本(大多数更改都与以角度方式执行相关)

  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>