Reputation: 1872
Hi all I'm trying to get hold of my directive's "expanded" DOM. That is, I want to be able to find and manipulate the DOM elements that are generated by the directive. I thought that the link or postlink functions were supposed to do that, but I keep finding the un-expanded version of my template (or at least, the stuff that ng-repeat should be generating isn't there.) Here's my example. Notice that the count of "li" elements is zero in both the pre and post link functions, but after the timeout, there are five. I need to find the five, but without the dirty tricks of timeout! What's the proper way to find this structure so I can work with it?
EDIT:
OK, I believe I've determined that what's happening is that the template has indeed been substituted into the element (actually, seemingly by the time the pre link function is called. The problem is that it hasn't been "evaluated" (I think this stage is what the docs rather oddly call "interpolated") even by the time the post link function is called.
That is, if I put, in the body of my pre, post, and timeout functions below, a call to print the inner html of the element, I get:
pre/post html is<ul><!-- ngRepeat: item in list --></ul>
but after the timeout there are are bunch of <li>
elements. So, the question should really be "how do I get a callback after the template has been evaluated/interpolated?
(EDIT again, I've changed the code example below to be consistent with this new description!)
EDIT again to add suggested $compile (and use $timeout) I notice that this doesn't change anything. I think the problem is nothing to do with compilation as such, but to do with the expansion of the the ngRepeat, which seems to happen in a different "cycle" in some way.
<!doctype html>
<html data-ng-app="MyModule">
<body data-ng-controller="MyController">
<h1>Version 3</h1>
<test></test>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script>
angular.module('MyModule', [])
.controller('MyController', function ($scope) {
$scope.list = [1, 2, 3, 4, 5];
})
//.directive('test', function ($compile) {
.directive('test', function ($compile, $timeout) {
return {
template: '<ul><li ng-repeat=" item in list ">{{item}}</li></ul>',
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
//console.log('pre, li count is ' + iElement.find('li').length);
console.log('pre html is' + iElement.html());
},
post: function postLink(scope, iElement, iAttrs, controller) {
//console.log('post, li count is ' + iElement.find('li').length);
console.log('post html is' + iElement.html());
iElement.append($compile(this.template)(scope));
console.log('post-compile html is' + iElement.html());
//setTimeout(() =>
$timeout(() =>
console.log('post timeout, li count is '
//+ tElement.find('li').length),
+ tElement.html()),
10, true);
}
}
}
};
});
</script>
</body>
</html>
TIA, Toby
Upvotes: 1
Views: 993
Reputation: 22323
In your link
function, you can use the $compile
service to "complete" the compilation process. something like the following:
return {
link: function(scope, element) {
var template = '<ul><li ng-repeat=" item in list ">{{item}}</li></ul>';
var linkFn = $compile(template);
var content = linkFn(scope);
element.append(content);
}
}
This will produce a complete DOM element that can be traversed. you can either modify content
before appending it, or element
after the content
has been appended.
You will frequently see the shorthand of this process, i.e.:
var content = $compile(template)(scope);
Upvotes: 1