如何使 ng-bind-html 编译 angularjs 代码
Posted
技术标签:
【中文标题】如何使 ng-bind-html 编译 angularjs 代码【英文标题】:How to make ng-bind-html compile angularjs code 【发布时间】:2013-11-12 14:52:01 【问题描述】:我正在使用 angularjs 1.2.0-rc.3。我想将 html 代码动态地包含到模板中。为此我在控制器中使用:
html = "<div>hello</div>";
$scope.unicTabContent = $sce.trustAsHtml(html);
在我得到的模板中:
<div id="unicTab" ng-bind-html="unicTabContent"></div>
它适用于常规 html 代码。但是当我尝试放置角度模板时,它不会被解释,它只是包含在页面中。例如,我想包括:
<div ng-controller="formCtrl">
<div ng-repeat="item in content" ng-init="init()">
</div>
</div>
非常感谢
【问题讨论】:
是的,这并不是 Angular 想要的工作方式。如果要动态添加 html,请查看$complie
服务。
为什么不使用ngScript创建about模板,然后使用ng-include,ng-src添加它
【参考方案1】:
一种方法是使用指令来插入包含角度表达式的自定义模板
<div id="unicTab" unic-tab-content></div>
app.directive("unicTabContent",function()
return
restrict:"A",
template:'unicTabContent'
)
【讨论】:
我喜欢这个想法,它确实包含了代码,但仍然没有编译。 和plnkr.co/edit/sUOxHBUYIdQlAiM3Dy0V?p=preview 一样在这里工作得很好,也许你有一些嵌套指令或其他导致它不起作用的东西 但我希望它能够编译您调用 test.xml 的变量中的代码。例如plunker 显示 和 ,这不是我想要的。 OK..可以用link
指令回调Plunker来做到这一点
确实可以编译 html,但不能编译 angular 语句。在Plunker 中,当直接注入测试变量时,ng-click 方法已连接,但使用指令注入时则没有。【参考方案2】:
正如 Vinod Louis 在他的评论中所说,最好的方法是使用模板。我必须在常规代码之外定义一个模板,例如我在 index.html 中添加了该代码:
<script type="text/ng-template" id="unic_tab_template.html">
<div ng-switch on="page">
<div ng-switch-when="home"><p>home</p></div>
<div ng-switch-when="form">
<div ng-controller="formCtrl">
<div ng-repeat="item in content">item.name:item.value</div>
</div>
</div>
<div ng-switch-default>an error accured</div>
</div>
</script>
此模板是有条件的,因此根据 $scope.page 的值,它会在 3 个模板之间切换(第三个是错误处理程序)。要使用它,我有:
<div id="unicTab" ng-controller="unicTabCtrl">
<div ng-include="'unic_tab_template.html'"></div>
</div>
这样我的页面会根据我的 unicTabCtrl 控制器中的 $scope 而改变。
总结一下很难实现插入 angularsjs 模板接缝的想法($compile seams 是解决方案,但我无法使其工作)。但您可以改为使用条件模板。
【讨论】:
我喜欢这个解决方案,但是如果我们能看到一个 HTML 来自其他地方的示例会更好(例如远程 JSON,因此在项目中没有硬编码)。跨度> 【参考方案3】:我试图做同样的事情并遇到了这个模块。
http://ngmodules.org/modules/ng-html-compile
我只是包含它,然后我就可以使用“ng-html-compile”而不是“ng-bind-html”
【讨论】:
【参考方案4】:此解决方案不使用硬编码模板,您可以编译嵌入在 API 响应中的 Angular 表达式。
第 1 步。 安装此指令:https://github.com/incuna/angular-bind-html-compile
第 2 步。 在模块中包含指令。
angular.module("app", ["angular-bind-html-compile"])
第 3 步。 使用模板中的指令:
<div bind-html-compile="letterTemplate.content"></div>
结果:
控制器对象
$scope.letter = user: name: "John"
JSON 响应
"letterTemplate":[
content: "<span>Dear letter.user.name,</span>"
]
HTML 输出 =
<div bind-html-compile="letterTemplate.content">
<span>Dear John,</span>
</div>
为了参考,下面是相关指令:
(function ()
'use strict';
var module = angular.module('angular-bind-html-compile', []);
module.directive('bindHtmlCompile', ['$compile', function ($compile)
return
restrict: 'A',
link: function (scope, element, attrs)
scope.$watch(function ()
return scope.$eval(attrs.bindHtmlCompile);
, function (value)
element.html(value);
$compile(element.contents())(scope);
);
;
]);
());
【讨论】:
这个 jsfiddle 有助于说明ng-bind-html
和 bind-html-compile
之间的编译差异:jsfiddle.net/HB7LU/14557
我想在我意识到这将如何简单地解决我的问题之前,我曾三次问过这个问题。如果可以的话,我会投票两次。【参考方案5】:
我在不使用模板的情况下在当前应用程序中解决类似问题(不优雅,但有效):
directive('ngBindHtmlCompile', ['$compile', function ($compile)
return
restrict: 'A',
compile: function compile(tElement, tAttributes, transcludeFn)
return function postLink(scope, element, attributes)
scope.$watch(function()
return scope.$eval(attributes.ngBindHtml);
, function(newValue, oldValue)
$compile(element.children())(scope);
);
;
;
]);
它需要ngBindHtml
在同一个元素上,并在元素内容更改为ngBindHtml
后编译。
<div id="unicTab" ng-bind-html="unicTabContent" ng-bind-html-compile></div>
ng-html-compile
看起来很相似,但乍一看它不会在模板内容发生变化时重新计算。但我没试过。
【讨论】:
【参考方案6】:这是我做的,不知道是不是角度的方式TM,但它工作并且超级简单;
.directive('dynamic', function($compile)
return
restrict: 'A',
replace: true,
link: function (scope, element, attrs)
scope.$watch(attrs.dynamic, function(html)
$compile(element.html(html).contents())(scope);
);
;
);
所以;
<div id="unicTab" dynamic="unicTabContent"></div>
编辑:我找到了角度方式,它超级简单。
$templateCache.put('unicTabContent', $sce.trustAsHtml(html));
<div id="unicTab" ng-include="'unicTabContent'"></div>
不需要制定自己的指令或任何东西。 但这是一种绑定一次的交易,it wont see changes made to your html 就像 the custom directive does。
【讨论】:
我发现这个答案是最容易实现的。 嘿,为什么在这里使用 $watch?为什么不直接用编译后的内容替换元素呢?谢谢顺便说一句。 这样如果变量发生变化,该变化将反映在下一个digest
的DOM 中。如果你的变量永远不会改变,你可以简化这一点,当然,但每当我提出答案时,我都会尽量保持它的通用性和普遍适用性。对于我的具体情况,我认为当指令被评估时我的变量是空的,所以我需要 watch
来表示变量最终被填充的时候。
这对我来说效果更好!特别是如果您也使用带有元素的过滤器,那么这绝对是要走的路。如果使用 angular-bind -html-compile 东西,我会达到摘要限制
有什么方法可以使 ng-html-compile 有条件?我的意思是仅在特定条件下附加/分配指令,例如 - 网格行单击并正常运行?【参考方案7】:
使用 Angular 内置的 $interpolate 和 $sce 对象,下面的代码要简单得多。首先将 $interpolate 和 $sce Angular 对象注入到您的指令中,就像您在指令中执行任何您需要的自定义操作一样。
amqApp.directive('myDir', ['$interpolate', '$sce', function ($interpolate,$sce ) ...
然后创建在导入的 html 表达式中找到的所有作用域变量...
$scope.custom = 'Hello World';
接下来使用 $interpolate 处理您的自定义 HTML 及其表达式...然后确保在绑定之前使用 $sce 对象将其信任为 HTML...
var html = $interpolate('<b>custom</b>')($scope);
$scope.data = $sce.trustAsHtml(html);
最后,在您的视图中,只需确保在视图显示中使用带有“ng-bind”或“ng-bind-html”的元素。我发现 $sce 片段不会将 HTML 显示为 HTML(将其视为文本),如果您不将它绑定到这样的 html 模板中...
<span ng-bind-html="data"></span>
你应该看到粗体...
你好世界
我使用这个技巧从 web.config 导入带有自定义角度 expressions 的文本/HTML。
【讨论】:
【参考方案8】:@clement-roblot 基于内置模板的大量简化解决方案。
控制器:
app.controller('TestCtrl', [
'$scope',
'$templateCache',
function ($scope, $templateCache)
$templateCache.put('test.html', '2 + 2 = 2 + 2 ');
]);
查看:
<div ng-include="'test.html'"></div>
【讨论】:
以上是关于如何使 ng-bind-html 编译 angularjs 代码的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ng-bind-html 插入 Angular 1.5 组件