【问题标题】:Insert an angular js template string inside an element在元素内插入角度 js 模板字符串
【发布时间】:2013-01-28 14:27:51
【问题描述】:

我试图将一些有角度的 js 模板字符串放在一个元素中,并期望得到一个编译的输出。但这并没有发生。

HTML

<div ng-controller="testController">
    <div ng-bind-html-unsafe="fruitsView"></div>
</div>

控制器:

function filterController($scope){
    ...
    $scope.arr = ["APPLE", "BANANA"];
    $scope.fruitsView = '<div><p ng-repeat="each in arr">{{each}}</p></div>';
}

输出只是{{each}}

那么我如何在元素中插入一个有角度的 js 模板字符串(此处为 $scope.fruitsView)?

我为此创建了fiddle

【问题讨论】:

  • 为什么要从控制器生成 HTML?
  • 你能解决这一切吗?
  • 我解决这个问题的用例:我正在使用第 3 方库(传单),我想在其中插入一些对 Angular 范围内的变化做出反应的控件。我想避免使用 vanilla DOM API 创建元素并使用$scope.$observe 更改它们,因为这与注册普通事件侦听器基本相同。

标签: angularjs


【解决方案1】:

在这种情况下,您不想只是“插入 HTML”,而是编译它。您可以使用$compile 服务创建 DOM 节点。

var tpl = $compile( '<div><p ng-repeat="each in arr">{{each}}</p></div>' )( scope );

如您所见,$compile 返回一个函数,该函数将作用域对象作为参数,根据该函数评估代码。例如,可以使用element.append() 将生成的内容插入到 DOM 中。

重要提示:但在任何情况下都不会有任何与 DOM 相关的代码属于您的控制器。正确的位置是 always 一个指令。这段代码可以很容易地放入指令中,但我想知道你为什么要以编程方式插入 HTML。

您能否在这里阐明一些问题,以便我提供更具体的答案?

更新

假设您的数据来自服务:

.factory( 'myDataService', function () {
  return function () {
    // obviously would be $http
    return [ "Apple", "Banana", "Orange" ];
  };
});

您的模板来自服务

.factory( 'myTplService', function () {
  return function () {
    // obviously would be $http
    return '<div><p ng-repeat="item in items">{{item}}</p></div>';
  };
});

然后创建一个简单的指令,读取提供的模板,对其进行编译,并将其添加到显示中:

.directive( 'showData', function ( $compile ) {
  return {
    scope: true,
    link: function ( scope, element, attrs ) {
      var el;

      attrs.$observe( 'template', function ( tpl ) {
        if ( angular.isDefined( tpl ) ) {
          // compile the provided template against the current scope
          el = $compile( tpl )( scope );

          // stupid way of emptying the element
          element.html("");

          // add the template content
          element.append( el );
        }
      });
    }
  };
});

那么在你看来:

<div ng-controller="MyCtrl">
   <button ng-click="showContent()">Show the Content</button>
   <div show-data template="{{template}}"></div>
</div>

在控制器中,您只需将其绑定在一起:

.controller( 'MyCtrl', function ( $scope, myDataService, myTplService ) {
  $scope.showContent = function () {
    $scope.items = myDataService(); // <- should be communicated to directive better
    $scope.template = myTplService();
  };
});

它们应该一起工作!

PS:这都是假设您的模板来自服务器。如果没有,那么您的模板应该在指令中,这样可以简化事情。

【讨论】:

  • 当用户单击 an 元素时,我想在页面中插入一个列表(我的问题中的相同列表模板)。我们可以在控制器中不进行 dom 操作的情况下处理这个用例吗?
  • +rajkamal 绝对!所以我可以用更具体的代码更新我的答案,点击的元素与插入内容的元素相同还是不同的元素?
  • 我一直遇到这个错误:Error: Argument 'scope' is required 使用 $compile 函数。我发现我使用两个参数错误地调用了该函数,如下所示:$compile(tpl, scope); 并且对于 $compile 是一个返回函数的函数完全视而不见,而是应该像这样调用它:$compile(tpl)(scope);,就像你一样应该是。只是发布这个以防其他人犯这个错误。
  • 我看到了 showData 但没有看到它在任何地方使用。缺少什么?
  • @jcollum 从视图中使用;它是 div 上的“显示数据”属性。 AngularJS 指令在视图中是蛇形,在 JavaScript 中是驼峰式。
猜你喜欢
  • 2018-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多