DOM is not ready for directory link function. Is a hacker timeout the only solution?

I use ng-repeat inside the directive template.

 myApp.directive("test", function () { return { restrict: 'C', scope: { bindVar: '=' }, template: '<div>\ <div class="item" ng-repeat="sel in bindVar">{{sel.display}}</div>\ </div>', link: function ($scope, element, attrs) { // setTimeout(function() { alert($('.item').length); // <--- RETURNS 0, IF I ADD TIMEOUT RETURNS 3 // },0); } // of link } // of return }); 

http://jsfiddle.net/foreyez/t4590zbr/

However, when the link() function is called, I don't seem to get access to the elements that were created. To do this, I need to set the timeout to 0 (after that it works).

I read this in the following article: http://lorenzmerdian.blogspot.com/2013/03/how-to-handle-dom-updates-in-angularjs.html

I also saw a similar answer in which the OP marked "Timeout" as the answer: DOM elements not ready in the link () function of the Directular function ,

But come on, there must be another way!

I cross my fingers that this hacking solution is wrong, and there is a way that angular provides a callback when the DOM was created using the directive. Or am I really relying on ... timeouts? (really?:/)

+4
source share
3 answers

$timeout , in fact, is a legitimate way to solve this problem if you use inline template (unlike templateUrl ). This would not create race conditions.

What happens, Angular goes through the DOM and collects the directives and their functions before and after the link (by compiling the directives). Then, the communication functions for each directive for each node (i.e., the DOM element) are executed.

Usually the template for node (to which the directive applies) is already part of the DOM. So, if you have the following directive:

 .directive("foo", function(){ return { template: '<span class="fooClass">foo</span>', link: function(scope, element){ // prints "<span class="fooClass">foo</span>" console.log(element.html()); } } } 

he can find the element $(".fooClass") .

However, if the directive uses transclude: 'element' , for example ng-if ( ngIf.js ) and ng-repeat ( ngRepeat.js ), Angular rewrites the directive as a comment ( compile.js ), and therefore $(".item") ( in your example) does not exist until ng-repeat places it there. They do this in their scope.$watch ( ngIf.js ) function , depending on the value that they are viewing, and this may happen in the next digest loop. That way, even when your post link function works, the actual element you are looking for still does not exist.

 .directive("foo", function(){ return { template: '<span ng-if="true" class="fooClass">foo</span>', link: function(scope, element){ // prints "<!-- ngIf: true -->" console.log(element.html()); } } } 

But there will be - definitely - when $timeout starts.

+4
source

How do I do this with a different directive. As an example:

 .directive('elementReady', function() { return { restrict: 'A', link: function(scope, elem, attr) { //In here, you can do things like: if(scope.$last) { //this element is the last element in an ng-repeat } if(scope.$first) { //first element in ng-repeat } //do jQuery and javascript calculations (elem has been added to the DOM at this point) } }; }); <table class="box-table" width="100%"> <thead> <tr> <th class='test' scope="col" ng-repeat="column in listcolumns" element-ready>{{column.title}}</th> </tr> </thead> </table> 

Obviously, you will need to configure how you distribute these events to your outer area ($ emit, through related functions, etc.).

+1
source

Taking Joe Answer and another answer I found on stackoverflow, I was able to do this:

 myApp.directive('myRepeatDirective', function() { return function(scope, element, attrs) { if (scope.$last){ scope.$emit('LastElem'); } }; }); 

and then in my source link:

  $scope.$on('LastElem', function(event){ alert($('.item').length); }); 

and the template looks like this:

 <div> <div class="item" ng-repeat="sel in bindVar" my-repeat-directive>{{sel.display}}</div> </div> 

http://jsfiddle.net/foreyez/t4590zbr/3/

but i still don't like this solution .. seems like blehhh

+1
source

Source: https://habr.com/ru/post/972199/


All Articles