从数据库编译动态 HTML 字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18157305/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compiling dynamic HTML strings from database
提问by giraffe_sense
The Situation
情况
Nested within our Angular app is a directive called Page, backed by a controller, which contains a div with an ng-bind-html-unsafe attribute. This is assigned to a $scope var called 'pageContent'. This var gets assigned dynamically generated HTML from a database. When the user flips to the next page, a called to the DB is made, and the pageContent var is set to this new HTML, which gets rendered onscreen through ng-bind-html-unsafe. Here's the code:
嵌套在我们的 Angular 应用程序中的是一个名为 Page 的指令,由一个控制器支持,它包含一个带有 ng-bind-html-unsafe 属性的 div。这被分配给一个名为“pageContent”的 $scope 变量。这个 var 是从数据库中动态生成的 HTML 分配的。当用户翻到下一页时,会调用数据库,并将 pageContent 变量设置为这个新的 HTML,它通过 ng-bind-html-unsafe 呈现在屏幕上。这是代码:
Page directive
页面指令
angular.module('myApp.directives')
.directive('myPage', function ($compile) {
return {
templateUrl: 'page.html',
restrict: 'E',
compile: function compile(element, attrs, transclude) {
// does nothing currently
return {
pre: function preLink(scope, element, attrs, controller) {
// does nothing currently
},
post: function postLink(scope, element, attrs, controller) {
// does nothing currently
}
}
}
};
});
Page directive's template("page.html" from the templateUrl property above)
Page 指令的模板(来自上面 templateUrl 属性的“page.html”)
<div ng-controller="PageCtrl" >
...
<!-- dynamic page content written into the div below -->
<div ng-bind-html-unsafe="pageContent" >
...
</div>
Page controller
页面控制器
angular.module('myApp')
.controller('PageCtrl', function ($scope) {
$scope.pageContent = '';
$scope.$on( "receivedPageContent", function(event, args) {
console.log( 'new page content received after DB call' );
$scope.pageContent = args.htmlStrFromDB;
});
});
That works. We see the page's HTML from the DB rendered nicely in the browser. When the user flips to the next page, we see the next page's content, and so on. So far so good.
那个有效。我们看到来自 DB 的页面 HTML 在浏览器中呈现得很好。当用户翻到下一页时,我们会看到下一页的内容,依此类推。到现在为止还挺好。
The Problem
问题
The problem here is that we want to have interactive content inside of a page's content. For instance, the HTML may contain a thumbnail image where, when the user clicks on it, Angular should do something awesome, such as displaying a pop-up modal window. I've placed Angular method calls (ng-click) in the HTML strings in our database, but of course Angular isn't going to recognize either method calls or directives unless it somehow parses the HTML string, recognizes them and compiles them.
这里的问题是我们希望在页面内容中包含交互式内容。例如,HTML 可能包含一个缩略图,当用户点击它时,Angular 应该做一些很棒的事情,比如显示一个弹出式模式窗口。我已经在我们数据库的 HTML 字符串中放置了 Angular 方法调用(ng-click),但当然 Angular 不会识别方法调用或指令,除非它以某种方式解析 HTML 字符串,识别它们并编译它们。
In our DB
在我们的数据库中
Content for Page 1:
第 1 页的内容:
<p>Here's a cool pic of a lion. <img src="lion.png" ng-click="doSomethingAwesone('lion', 'showImage')" > Click on him to see a large image.</p>
Content for Page 2:
第 2 页的内容:
<p>Here's a snake. <img src="snake.png" ng-click="doSomethingAwesone('snake', 'playSound')" >Click to make him hiss.</p>
Back in the Page controller, we then add the corresponding $scope function:
回到 Page 控制器,我们然后添加相应的 $scope 函数:
Page controller
页面控制器
$scope.doSomethingAwesome = function( id, action ) {
console.log( "Going to do " + action + " with "+ id );
}
I can't figure out how to call that 'doSomethingAwesome' method from within the HTML string from the DB. I realize Angular has to parse the HTML string somehow, but how? I've read vague mumblings about the $compile service, and copied and pasted some examples, but nothing works. Also, most examples show dynamic content only getting set during the linking phase of the directive. We would want Page to stay alive throughout the life of the app. It constantly receives, compiles and displays new content as the user flips through pages.
我不知道如何从数据库的 HTML 字符串中调用该“doSomethingAwesome”方法。我意识到 Angular 必须以某种方式解析 HTML 字符串,但是如何解析?我读过关于 $compile 服务的含糊不清的抱怨,并复制并粘贴了一些示例,但没有任何效果。此外,大多数示例显示动态内容仅在指令的链接阶段设置。我们希望 Page 在应用程序的整个生命周期中都保持活跃。当用户翻阅页面时,它不断接收、编译和显示新内容。
In an abstract sense, I guess you could say we are trying to dynamically nest chunks of Angular within an Angular app, and need to be able to swap them in and out.
从抽象的意义上讲,我想您可能会说我们正在尝试在 Angular 应用程序中动态嵌套 Angular 块,并且需要能够将它们交换进和交换出。
I've read various bits of Angular documentation multiple times, as well as all sorts of blog posts, and JS Fiddled with people's code. I don't know whether I'm completely misunderstanding Angular, or just missing something simple, or maybe I'm slow. In any case, I could use some advice.
我已经多次阅读了各种 Angular 文档,以及各种博客文章和 JS Fiddled with people's code。我不知道我是否完全误解了 Angular,或者只是遗漏了一些简单的东西,或者我很慢。无论如何,我可以使用一些建议。
回答by Buu Nguyen
ng-bind-html-unsafe
only renders the content as HTML. It doesn't bind Angular scope to the resulted DOM. You have to use $compile
service for that purpose. I created this plunkerto demonstrate how to use $compile
to create a directive rendering dynamic HTML entered by users and binding to the controller's scope. The source is posted below.
ng-bind-html-unsafe
仅将内容呈现为 HTML。它不会将 Angular 范围绑定到结果 DOM。您必须$compile
为此目的使用服务。我创建了这个 plunker来演示如何使用$compile
创建一个指令来呈现用户输入的动态 HTML 并绑定到控制器的范围。源码贴在下面。
demo.html
演示.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="[email protected]" data-semver="1.0.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<h1>Compile dynamic HTML</h1>
<div ng-controller="MyController">
<textarea ng-model="html"></textarea>
<div dynamic="html"></div>
</div>
</body>
</html>
script.js
脚本.js
var app = angular.module('app', []);
app.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
link: function (scope, ele, attrs) {
scope.$watch(attrs.dynamic, function(html) {
ele.html(html);
$compile(ele.contents())(scope);
});
}
};
});
function MyController($scope) {
$scope.click = function(arg) {
alert('Clicked ' + arg);
}
$scope.html = '<a ng-click="click(1)" href="#">Click me</a>';
}
回答by Alexandros Spyropoulos
In angular 1.2.10 the line scope.$watch(attrs.dynamic, function(html) {
was returning an invalid character error because it was trying to watch the value of attrs.dynamic
which was html text.
在 angular 1.2.10 中,该行scope.$watch(attrs.dynamic, function(html) {
返回了无效字符错误,因为它试图查看attrs.dynamic
html 文本的值。
I fixed that by fetching the attribute from the scope property
我通过从 scope 属性中获取属性来解决这个问题
scope: { dynamic: '=dynamic'},
My example
我的例子
angular.module('app')
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
scope: { dynamic: '=dynamic'},
link: function postLink(scope, element, attrs) {
scope.$watch( 'dynamic' , function(html){
element.html(html);
$compile(element.contents())(scope);
});
}
};
});
回答by kwerle
Found in a google discussion group. Works for me.
在谷歌讨论组中找到。为我工作。
var $injector = angular.injector(['ng', 'myApp']);
$injector.invoke(function($rootScope, $compile) {
$compile(element)($rootScope);
});
回答by Rupesh Kumar Tiwari
You can use
您可以使用
ng-bind-html https://docs.angularjs.org/api/ng/service/$sce
ng-bind-html https://docs.angularjs.org/api/ng/service/$sce
directive to bind html dynamically. However you have to get the data via $sce service.
动态绑定 html 的指令。但是,您必须通过 $sce 服务获取数据。
Please see the live demo at http://plnkr.co/edit/k4s3Bx
请在http://plnkr.co/edit/k4s3Bx查看现场演示
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,$sce) {
$scope.getHtml=function(){
return $sce.trustAsHtml("<b>Hi Rupesh hi <u>dfdfdfdf</u>!</b>sdafsdfsdf<button>dfdfasdf</button>");
}
});
<body ng-controller="MainCtrl">
<span ng-bind-html="getHtml()"></span>
</body>
回答by Ramesh M
Try this below code for binding html through attr
试试下面的代码,通过 attr 绑定 html
.directive('dynamic', function ($compile) {
return {
restrict: 'A',
replace: true,
scope: { dynamic: '=dynamic'},
link: function postLink(scope, element, attrs) {
scope.$watch( 'attrs.dynamic' , function(html){
element.html(scope.dynamic);
$compile(element.contents())(scope);
});
}
};
});
Try this element.html(scope.dynamic); than element.html(attr.dynamic);
试试这个 element.html(scope.dynamic); 比 element.html(attr.dynamic);