I am using the AngularJs-UI components for Bootstrap. I would like to insert a filled out template into one of the data elements for the popover feature. This works find for all elements not inside of a ng-repeat. How do I get the ng-repeat elements to work inside of a interpolated template?
I have a plunker at http://plnkr.co/edit/Cuku7qaUTL1lxRkafKzv Its not working because I don't know how to get Angular-UI-bootstrap to in plunker.
<div data-popover="{{createHTML()}}">some content</div>
My local scope has the function createHTML()
that looks something like this.
angular.module('myApp', ['ngSanitize'])
.controller("myController", function(myService){
$scope.createHTML = function() {
var thingy = { blah: "foobar", collection: [ "1", "2", "3" ] };
return myService.html_for(thingy);
}
});
And the service is
angular.module('myApp')
.service('myService', function($templateCache, $interpolate, $sanitize, $log) {
"use strict";
function html_for(thingy) {
var template = $templateCache.get('thingyTemplate.html'),
link = $interpolate(template),
html = link(thingy),
unsafe = $sanitize(html);
return unsafe;
}
return {
html_for: html_for
}
});
Templates:
<script type="text/ng-template" id="thingyTemplate.html">
<div>
<div><strong>Blah:</strong> {{blah}}</div>
<div data-ng-repeat="foo in collection"><strong>Collection:</strong> {{foo}}</div>
<div><strong>Collection[0]:</strong> {{collection[0]}}</div>
<div><strong>Collection[1]:</strong> {{collection[1]}}</div>
<div><strong>Collection[2]:</strong> {{collection[2]}}</div>
</div>
</script>
<script type="text/ng-template" id="template/popover/popover.html">
<div class="popover {{placement}}" data-ng-class="{ in: isOpen(), fade: animation() }">
<div class="arrow"></div>
<div class="popover-inner">
<h3 class="popover-title" data-ng-bind="title" data-ng-show="title"></h3>
<div class="popover-content" data-ng-bind-html="content"></div>
</div>
</div>
</script>
$interpolate
doesn't handle directives likengRepeat
( Difference between parse, interpolate and compile ).$interpolate
:To handle
ngRepeat
and other directives you want$compile
. But for your use case$compile
is going to result, unfortunately, in a number of changes because:It needs a scope to compile against rather than just a context like
$interpolate
. Moreover it needs the scopethingy
is on.This means we'll need to reference your properties like so {{thingy.blah}} instead of {{blah}} inside your template.
The compile needs to happen when the popup is on the dom.
So we can't just replace
$interpolate
with$compile
inside your service.One approach is to replace
data-ng-bind-html
with the following directive that acts like anng-bind-html
that has a built in$compile
(clearly you should only use this with html that you know is safe).Used like so (with
compile
replacingng-bind-html
:One issue is that we need
thingy
to be in scope. There's a few of ways of handling that- but for demonstration purposes I've manually gone back up to the scope the popover is called from - which is 2 scopes up thus thescope.$parent.$parent
.Using this compile directive you no longer
$interpolate
or$sanitize
so the function in your service can shrink down to just returning the appropriate template:demo fiddle