0

I'm trying to access DOM element in Directive's link function. The element is located in the view of another directive. Here is the code:

first directive

    (function () {
        'use strict';
        angular.module("testAPP",[])


        .directive('firstDirective', function(){
            var directive = {
                 restrict: 'E',
                 templateUrl: 'firstDirective.html'
                }
                return directive;
        })
  })();

second directive

(function () {
      'use strict';
       angular.module("testAPP",[])
        .directive('anotherDirective', function(){
             var directive = {
                restrict: 'E',
                templateUrl: 'anotherDirective.html',
                link: function($scope){
                  //element from another directive's view

                  var height = document.getElementByClassName("sky")[0].offsetHeight;
                }
             };
             return directive;

           });
     })();

There is a console error saying that height variable is undefined. I tried timeout function and that worked for me, but i think it's not a good solution:

setTimeout(function(){
  var height = document.getElementByClassName("sky")[0].offsetHeight;
  console.log(height);
});

I also tried "require", but it caused an error that the directive can't be found (i think this might be because that directives are located in separate directories)

So, could you tell me the reason why require does not work, and suggest me better solution than timeout

Ketevan Toria
  • 109
  • 1
  • 14

3 Answers3

1

Besides the fact that this doesn't seem like a very good idea in the first place and would be considered as "bad practice" - you will have to change the priorities of your directives in order to let them compile in the order you need them to compile, to make sure that the first directive is ready when the second one tries to access the elements.

Patrick Kelleter
  • 2,631
  • 1
  • 13
  • 19
  • timeout method proves that second directive loads late, but i do not know the reason. in html they are called correctly: – Ketevan Toria Mar 04 '16 at 11:07
  • as mentioned before you will have to change their compilation priority in order to make them compile in the order you want them to compile. this has nothing to do with the order in your html of the directives. it is about the "priority" parameter for directives which you can find in the angular documentation – Patrick Kelleter Mar 04 '16 at 12:59
  • hm, i found that useful : **priority** When there are multiple directives defined on a single DOM element, sometimes it is necessary to specify the order in which the directives are applied. The priority is used to sort the directives before their compile functions get called. Priority is defined as a number. Directives with greater numerical priority are compiled first. Pre-link functions are also run in priority order, but post-link functions are run in reverse order. The order of directives with the same priority is undefined. The default priority is 0. **thanks** – Ketevan Toria Mar 04 '16 at 13:34
1

I think, your content directive load before your 2nd directive, Add ng-if on your content directive may fix the issue

    angular.module("testAPP",[])
                .directive('secondDirective', function(){
       var directive = {
       restrict: 'E',
       templateUrl: 'secondDirective.html',
       link: function($scope){
           $scope.scondDirctiveLoaded = true;
       }
     };
     return directive;
    });

<second-directive></second-directive>
<div ng-if="scondDirctiveLoaded">
    <content-directive  ng-if="scondDirctiveLoaded" ></content-directive>
</div>
byteC0de
  • 5,153
  • 5
  • 33
  • 66
  • could you please write a little example of your idea? i couldn't get it – Ketevan Toria Mar 04 '16 at 11:10
  • @KetevanToria Pls check now – byteC0de Mar 04 '16 at 11:49
  • adding ng-if really is a bad solution for the given issue and even is a less "good practice" than using a timeout is. even if it works it doesn't make it a good solution. i strongly recommending not using this answer for your projects. its nothing more than a workaround which will lead to unmaintainable complex code – Patrick Kelleter Mar 04 '16 at 13:02
1

This error happens as the directive is instantiated before the DOM is actually ready. $timeout works as it delays the grabbing of the element until Angulars next tick cycle - while this feels like an anti-pattern it seems to be an acceptable solution to the problem.

There is already an answer to a question similar to this.

How can I run a directive after the dom has finished rendering?

Community
  • 1
  • 1
Sten Muchow
  • 6,623
  • 4
  • 36
  • 46