Javascript 以编程方式将角度模板编译为HTML字符串

Javascript 以编程方式将角度模板编译为HTML字符串,javascript,angularjs,Javascript,Angularjs,在我的Angular 1.5.11应用程序中,我试图以编程方式编译一个模板,并将结果作为HTML字符串。模板的内容是 <div ng-if="foo"> <div>foo is {{foo}}, bar is {{bar}}</div> </div> foo是{{foo}},bar是{{bar} 我试图将其编译为HTML字符串: app.controller('MainCtrl', function($scope, $rootScope

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

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

foo是{{foo}},bar是{{bar}
我试图将其编译为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;
});
app.controller('MainCtrl',函数($scope、$rootScope、$compile){
函数compileHtmlTemplate(模板内容、模型){
var templateScope=$rootScope.$new(true);
角度扩展(模板范围、模型);
返回$compile(templateContent)(templateScope);
}
var templateContent=$('#template').html();
var模型={foo:'fooValue',bar:'barValue'};
var compiledHtml=compileHtmlTemplate(模板内容,模型);
var htmlAsString=$('').html(compiledHtml.html();
$scope.result=htmlastring;
});

但是,正如您在本文中看到的,它不起作用。我需要编译模板,而不仅仅是插入模板,因为它包含一个
ng if
指令。

是的,您可以像这样使用$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;
});
var-app=angular.module('plunker',['ngSanitize']);
app.controller('MainCtrl',函数($scope、$rootScope、$compile、$interpolate){
函数compileHtmlTemplate(模板内容、模型){
var templateScope=$rootScope.$new(true);
角度扩展(模板范围、模型);
var tpl=$compile(templateContent)(templateScope);
控制台日志(tpl);
返回$interpolate(tpl.html(),model)
}
var templateContent=$('#template').html();
var模型={foo:'fooValue',bar:'barValue'};
var compiledHtml=compileHtmlTemplate(模板内容)(模型);
//console.log(compiledHtml)
var htmlAsString=$('').html(compiledHtml.html();
$scope.result=htmlastring;
});
使用模型插值返回已编译的html,然后使用相同的方法

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


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);
});
var-app=angular.module('plunker',['ngSanitize']);
app.controller('MainCtrl',函数($scope、$rootScope、$compile、$timeout、$templateCache){
函数compileHtmlTemplate(模板内容、模型){
var templateScope=$rootScope.$new(true);
角度扩展(模板范围、模型);
var compiled=$compile(templateContent)(templateScope);
var parent=$(“”).html(已编译);
console.log(“不起作用!摘要尚未完成:”,父[0].innerHTML);
$timeout(function(){//必须等待Angular完成摘要
console.log('将起作用,摘要现在已完成:',父项[0].innerHTML);
$scope.result=parent[0]。innerHTML;
}, 0);
}
//要么在$timeout内对编译后的值执行某些操作,要么观察它
$scope.$watch('result',函数(newValue,oldValue){
if(newValue!==未定义){
log(“在$timeout或此处执行操作…”+newValue);
}
});
//如果需要,可以通过模板缓存访问模板
var templateContent=$templateCache.get('template');
var模型={foo:'fooValue',bar:'barValue'};
var compiledHtml=compileHtmlTemplate(模板内容,模型);
});

更新的Plunker:

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

我已经更新了你的装备

var compiledHtml=compileHtmlTemplate(模板内容,模型);
var element=angular.element(“”).html(compiledHtml)
$timeout(函数(){
$scope.result=element.html()
})

由于模板中的
ngIf
,因此
compiledHtml
仅返回
ngIf
注释,我以前也曾遇到过这种情况,我提出的唯一解决方案就是如上所述,将
compiledHtml
附加到新创建的元素中,并在
$timeout
中检索html,而不指定时间,因为这将在附加和
$digest
循环之后发生。希望对您有所帮助

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

var templateContent=$templateCache.get(“模板”);
//var templateContent=$('#template').html();
//注释:以角度方式获取html,而不是使用jquery
var模型={foo:'fooValue',bar:'barValue'};
var templateScope=$rootScope.$new(true);
templateScope=angular.extend(templateScope,模型);
//角度扩展(模板范围、模型);
//注释:确保捕获angular.extend的结果
var compiledElement=$compile(templateContent)(templateScope);
//var compiledHtml=$compile(templateContent)(templateScope);
//注释:编译的结果不是一个html,而是一个角度元素
var targetElement=angular.element(“结果”);
//var htmlAsString=$('').html(compiledHtml.html();
//注释:使用angular而不是jquery查找元素
targetElement.append(compiledElement);
//$scope.result=htmlastring;
//注释:不要只指定字符串,还要附加一个角度元素
更新

html中的一个小变化是

  replaced
  <div>{{result}}</div>

  with
  <div id="result"></div>
已替换
{{result}}
具有

想发明轮子吗?或者你想得到什么?正如您在上一个问题中所评论的,您可能希望$interpolate而不是$compile。您需要$eval后面的值compiling@PetrAveryanov
$interpolate
无法工作,因为模板包含directives@blackmiaool
foo
有一个值,因此如果
ng
的计算结果为true.@estus OP没有说它没有用,有效问题;只是他们不想进一步解释。那完全是他们的特权。例如,细节可能是商业敏感的。而且,在10万美元的时候,它们已经存在了足够长的时间
  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
  replaced
  <div>{{result}}</div>

  with
  <div id="result"></div>