Reputation: 314
Having a little issue with angular that I can't figure out. I suspect it may have something to do with scope, but I'm not 100% exactly what.
Here's my HTML:
<i class="icon-question-sign" popover data-placement="top" data-trigger="hover" data-title="Top 10 clients" data-content-compile="<ul><li ng-repeat='client in user.clients | limitTo: 10'>{{client}}</li></ul>"></i>
Here's my directive:
app.directive('popover', function($timeout, $compile) {
var linker = function (scope, element, attrs) {
$timeout(function() {
var content = $compile(element.data('content-compile'))(scope);
element.popover({
'html': true,
'content': content
});
}, 200);
}
return {
restrict: 'A',
link: linker
}
});
The result correctly repeats li's to the correct length of {{user.clients}} but doesn't render {{client}}. For some reason, that comes through as blank, yet, it has a string value and works when added directly to the HTML and not compiled through the directive. How it currently looks in the DOM:
<ul class="ng-scope"><!-- ngRepeat: client in user.clients | limitTo: 10 --><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li><li ng-repeat="client in user.clients | limitTo: 10" class="ng-scope"></li></ul>
If I replace {{client}} with say {{user.email}} it lists correctly.
Not sure what's up here - I'm probably missing something obvious!
Upvotes: 3
Views: 3957
Reputation: 314
Seems the answer was a little more straight forward than I expected, changing my directive to:
// popover
app.directive('popover', function($timeout, $compile) {
var linker = function (scope, element, attrs) {
var content = $compile(element.data('content-compile'))(scope);
$timeout(function() {
element.popover({
'html': true,
'content': content
});
}, 400);
}
return {
restrict: 'A',
link: linker
}
});
The only difference is that I doubled the $timeout period, and moved the compiled variable outside of it. Ensuring the data is compiled before it's called.
Not 100% sure if this is the right way to do it, but under testing its returning correctly on all accounts. Although, if you have a similar problem - take this solution with a pinch of salt.
Upvotes: 0
Reputation: 12146
The key to your problem is it's cause: {{client}}
in data-content-compile gets compiled before directive kicks in, so client
would be undefined in controller context. Currently, the string you send into $compile is:
<ul><li ng-repeat='client in user.clients | limitTo: 10'></li></ul>
In order to prevent this, template has to be sent into directive some other way. Here are some:
I did an example using second approach:
<div ng-controller="ctrl">
<script type="text/ng-template" id="client.html">
<div><ul><li ng-repeat='client in user.clients'>{{client.name}}</li></ul></div>
</script>
<i
popover
class="glyphicon glyphicon-user"
data-placement="bottom"
data-trigger="hover"
data-title="Top 10 clients"
data-content-template="client.html"
></i>
</div>
angular.module("app", [])
.controller("ctrl", function($scope, User) {
$scope.user = User;
})
.directive("popover", function($compile, $timeout, $templateCache) {
return function(scope, el, attr) {
$timeout(function() {
el
.popover({
html: true,
content: $compile($templateCache.get(attr.contentTemplate))(scope)
})
.popover("show")
});
};
})
.value("User", {
clients: [
{ name: "John", age: 22},
{ name: "Ann", age: 13},
{ name: "Maria", age: 62},
{ name: "Ivan", age: 44}
]
});
Upvotes: 2