AngularJS - Compiling dynamic HTML strings from database
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.
No comments:
Post a Comment