6

是否可以编译这个 html 模板字符串:

"<p>List of products from {{supplier.name}}</p>
<p ng-repeat="ref in refs">{{ref}}</p>"

直接到一个 html 字符串,如:

"<p>List of products from Some Supplier</p>
<p>a0120</p>
<p>a0241</p>
<p>z1242</p>
<p>z3412</p>"

或者至少是不太干净的版本:

"<p class="ng-scope ng-binding">List of product from Duval</p>
<!-- ngRepeat: ref in refs track by $index -->
<p ng-repeat="ref in refs track by $index" class="ng-scope ng-binding">a0120</p>
<p ng-repeat="ref in refs track by $index" class="ng-scope ng-binding">a0241</p>
<p ng-repeat="ref in refs track by $index" class="ng-scope ng-binding">z1242</p>
<p ng-repeat="ref in refs track by $index" class="ng-scope ng-binding">z3412</p>"

我尝试使用 $compile(templateStr)($scope) 但返回的 dom 元素未完全处理。但是我没有使用以下指令将其编译为页面元素,并检查该元素我可以看到它具有我正在寻找的最终 html:

app.directive('compile', function($compile) {
    return{
        restrict: 'A',
        scope: {
            compile: '=compile',
            data: '=ngData'
        },
        link: function(scope, element, attrs) {
            scope.$watch('data',
                    function(value) {
                        for (var k in scope.data)
                            scope[k] = scope.data[k];
                    }
            )

            scope.$watch('compile',
                    function(value) {
                        element.html(value);
                        var a = $compile(element.contents())(scope);
                    }
            )
        }
    }
})

有什么方法可以直接从模板中获取最终的 html 吗?谢谢

PS:我在这里想要实现的是直接在 CKEditor 中编辑模板(在文本模式下,而不是源代码),最终才进入源代码模式以添加一些“ng-repeat”属性。使用像 Handlebars 这样的模板引擎需要 html 元素之外的占位符,并且会被 CKEditor 自动删除,因为它只处理 html。

可能的解决方案(hacky):一种可能的方法是在隐藏元素上使用编译指令并在控制器上加载视图后读取元素的内容:

$scope.$on('$viewContentLoaded', $scope.onLoaded);
$timeout(function() {
    var el =$("#text div")[0]
    cleanAngularStuff(el)
    $scope.currMailTemplate.processed = el.innerHTML
});

cleanAngularStuff 函数只是为了清理额外的角度指令和类。

如果有人想使用它或改进它,我会在这里发布。

在不向页面添加元素的情况下有更好的方法吗?

4

2 回答 2

4

您需要做的是在 $digest 循环之后访问已编译的元素。

因此,在 $digest 循环中,您可以执行以下操作:

templateString = '<some-template-code/>';
...
var compiled = $compile(templateString)(scope);
// scope.$digest // only call this if not within a $digest cycle

// you can do a $timeout to let the previous digest cycle complete
$timeout(function(){
  var theHtml = compiled[0].outerHTML;
  console.log('the html with the variables', theHtml);
});

如果您尚未处于摘要周期内,则需要手动调用scope.$digest(). 您可以在下面看到嵌入的示例。

(function(){
  "use strict";
  var app = angular.module('soApp', []);
  
  app.directive('showCompiledTemplate',[
            '$compile','$timeout',
    function($compile , $timeout) {
      return {
        restrict: 'E',
        template: '<div class="compiled-template">' +
			        '<div><textarea cols="40" rows="15" readonly></textarea></div>' +
          			'<div class="output"></div>' +
                  '</div>',
        scope: {
          data: '=',
          template: '='
        },
        link: function(scope,elem,attrs) {
            var textarea = elem.find('textarea')[0];
            var output = elem.children().children().eq(1);
			var updateOutput = function(tpl) {
                var compiled = $compile(tpl)(scope);
                $timeout(function(){
                    var theHtml = compiled[0].outerHTML;
                    textarea.value = theHtml;
                    output.html(theHtml);
                });
            };
            scope.$watch("template",function(tpl){
				updateOutput(tpl);
            });
            scope.$watch("data",function(){
                updateOutput(scope.template);
            },true);
        }
      };
    }
  ]);
  
  app.controller('MainCtrl', function() {
    this.data = {
      name: 'John',
      list: ['one duck','two ducks','three ducks']
    };
    //this.template = "<div>hi</div>";
    var template = '';
    template += '<div>\n';
    template += '  <p>{{data.name}}</p>\n';
    template += '  <ul>\n';
    template += '    <li ng-repeat="item in data.list">{{item}}</li>\n';
    template += '  </ul>\n';
    template += '</div>\n';
    this.template = template;
  });
  
 })();
.form-field {
    padding-bottom: 10px;
}
.form-field span {
    width: 70px;
    display: inline-block;
}
.compiled-template {
   display: -webkit-flex;
   display: flex;
   -webkit-flex-direction: row;
   flex-direction: row;
}
.compiled-template textarea {
    background-color: #eee;
    margin-right: 10px;
}
.compiled-template .output {
    border: 1px solid #ccc;
    padding: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app="soApp">
  <div ng-controller="MainCtrl as main">
      <div class="form-field">
          <span class="form-label">Name:</span>
          <input type="text" ng-model="main.data.name" /> <br/>
      </div>
      <div class="form-field">
          <span class="form-label">Template:</span>
          <textarea ng-model="main.template" cols="40" rows="8"></textarea> <br/>
      </div>
      <div>
          <show-compiled-template data="main.data" template="main.template" />
      <div>
  </div>
</div>

于 2015-09-24T20:07:53.327 回答
0

可以通过为您的指令提供模板来完成,如下所示。

app.directive('compile', function($compile) {
return{
    restrict: 'A',
    template: '<p>List of products from {{supplier.name}}</p>
               <p ng-repeat="ref in refs">{{ref}}</p>'
    scope: {
     refs: '='
     supplier: '='
    },
    link: function(scope, element, attrs) {
       # Your code goes here 
    }
}

})

于 2014-05-07T10:02:23.850 回答