从数据库编译动态HTML字符串 [英] Compiling dynamic HTML strings from database
问题描述
情况
在Angular应用程序中嵌套的是一个名为Page的指令,由一个控制器支持,其中包含一个带有ng-bind-html-unsafe属性的div 。这被分配给一个名为'pageContent'的$ scope var。这个var从数据库中获取动态生成的HTML。当用户翻到下一页时,会调用数据库,并将pageContent var设置为这个新的HTML,它通过ng-bind-html-unsafe在屏幕上呈现。以下是代码:
页面指令
<$ c $ ('myPage',function($ compile){
return {
templateUrl:'page.html') ,
restrict:'E',
编译:函数compile(元素,attrs,transclude){
//目前不做任何操作
return {
pre:function preLink (范围,元素,attrs,控制器){
//目前不做任何操作
},
post:function postLink(scope,element,attrs,controller){
//目前没有任何
}
}
}
};
});
Page指令的模板(page.html来自上面的templateUrl属性)
< div ng-controller =PageCtrl>
...
<! - 动态页面内容写入下面的div - >
< div ng-bind-html-unsafe =pageContent>
...
< / div>
页面控制器
($ scope){
$ b $ scope.pageContent = '';
$ b $ scope。$ on(receivedPageContent,function(event,args){
console.log('数据库调用后收到的新页面内容');
$ scope.pageContent = args.htmlStrFromDB;
});
});
有效。我们在浏览器中看到了来自数据库的页面HTML。当用户翻到下一页时,我们会看到下一页的内容,等等。到目前为止这么好。
问题
这里的问题是我们希望在一个页面的内容。例如,HTML可能包含一个缩略图图像,当用户点击它时,Angular应该做一些很棒的事情,比如显示一个弹出式模式窗口。我在数据库中的HTML字符串中放置了Angular方法调用(ng-click),但是当然Angular不会识别任何方法调用或指令,除非它以某种方式解析HTML字符串,识别它们并编译它们。 / p>
在我们的数据库中
第1页的内容:
< p>下面是一张很酷的狮子图片。 < img src =lion.pngng-click =doSomethingAwesone('lion','showImage')>点击他可以查看大图片。< / p>
第2页的内容:
< p>这是一条蛇。 < img src =snake.pngng-click =doSomethingAwesone('snake','playSound')>点击使他发出嘘声。< / p>
返回页面控制器,然后添加相应的$ scope函数:
页面控制器
$ scope.doSomethingAwesome = function(id ,action){
console.log(要做+ action +with+ id);
}
我无法弄清楚如何从内部调用'doSomethingAwesome'方法数据库中的HTML字符串。我意识到Angular必须以某种方式解析HTML字符串,但是如何?我读过关于$ compile服务的模糊混淆,并复制并粘贴了一些示例,但没有任何效果。另外,大多数示例显示的是动态内容只在指令的链接阶段进行设置。我们希望Page在应用程序的整个生命周期中保持活力。它会在用户翻页时不断接收,编译和显示新内容。
从抽象意义上讲,我想你可以说我们正试图在Angular应用程序中动态地嵌套Angular块,并且需要能够将它们交换出来。
我已经多次阅读了Angular文档的各个部分,以及各种博客帖子,以及JS用人们的代码弄了个手脚。我不知道我是否完全误解了Angular,或者只是错过了简单的东西,或者我很慢。在任何情况下,我都可以使用一些建议。
ng-bind-html-unsafe
仅将内容呈现为HTML。它不会将Angular范围绑定到结果DOM。您必须为此使用
$ compile
服务。我创建了这个plunker 来演示如何使用 $ compile
创建用户输入的动态HTML指令并绑定到控制器的作用域。
$ b demo.html
<!DOCTYPE html>
< html ng-app =app>
< head>
< script src =script.js>< / script>
< / head>
< body>
< h1>编译动态HTML< / h1>
< div ng-controller =MyController>
< textarea ng-model =html>< / textarea>
< div dynamic =html>< / div>
< / div>
< / body>
< / html>
script.js
var app = angular.module('app',[]);
app.directive('dynamic',function($ compile){
return {
restrict:'A',
替换为:true,
link:function(scope,ele,attrs){
scope。$ watch(attrs.dynamic,function(html){
ele.html(html);
$ compile(ele.contents ())(scope);
});
}
};
});
函数MyController($ scope){
$ scope.click = function(arg){
alert('Clicked'+ arg);
}
$ scope.html ='< a ng-click =click(1)href =#>点击我< / a>';
}
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:
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)
<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.
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.
In our DB
Content for Page 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:
<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 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.
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.
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.
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 plunker to 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.
demo.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js@1.0.7" 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
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>';
}
这篇关于从数据库编译动态HTML字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!