2013-02-13 27 views
29

我试图在元素中放置一些角度js模板字符串,并期望编译后的输出。但这并没有发生。在元素中插入角度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

+3

为什么从控制器生成HTML? – 2013-02-13 05:26:03

+0

你能解决这个问题吗? – 2013-02-17 07:38:30

+0

我对这个问题的用例:我正在使用第三方库(小册子),我想插入一些对Angular作用域中的更改作出反应的控件。我想避免使用vanilla DOM API创建元素,并使用'$ scope。$ observe'来更改它们,因为这与注册普通事件侦听器基本相同。 – fredrikekelund 2015-06-29 07:08:42

回答

95

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

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

正如你可以看到,$compile返回一个函数,它接受一个范围对象作为参数,针对其代码进行了评价。例如,可以将结果内容插入到DOM中,例如element.append()

重要提示:但是在任何情况下做任何DOM相关的代码在你的控制器属于。适当的地方是总是一个指令。这段代码很容易被引入指令中,但是我想知道为什么你会以编程方式插入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:这都假设你的模板来自服务器。如果没有,那么你的模板应该在指令中,这简化了事情。

+0

我想在页面中插入一个列表(在我的问题中相同的列表模板),当用户点击一个元素。我们可以处理这个用例而不用在控制器中执行dom操作吗? – rajkamal 2013-02-13 05:50:21

+0

+ rajkamal绝对!因此,我可以用更具体的代码来更新我的答案,clicked元素与插入内容的元素相同,还是不同的元素? – 2013-02-13 05:53:33

+0

其他不同的.. – rajkamal 2013-02-13 06:04:06