4

I have this directive:

    hpDsat.directive('ngElementReady', [function() {
        return {
            restrict: "A",
            link: function($scope, $element, $attributes) {
                // put watches here.
                console.log(" WHAT THE @#%*%$??? ");
                $scope.$eval($attributes.ngElementReady);
            }
        };
    }]);

I never see the output of the console.log. I'm declaring an element like this:

<div data-ng-element-ready="console.log(' ------------------------------- COMPILED! ')" data-ng-if="analysis.type" data-ng-show="showBasicHtml" data-ng-include="analysis.type+'Content.html'"></div>

Yes, I am declaring the directive before I declare the controller under which the div element exists. The element appears, ngShow and ngInclude works, and anything in the loaded template works just fine too (more directives, controllers, {{expressions}}, etc).

If I execute it with a compile function, the compile function does work, but still not the link function:

    hpDsat.directive('ngElementReady', [function() {
        return {
            restrict: "A",
            compile: function($element, $attributes) {
                console.log("This I do see."); // THIS WORKS!!
                return function($scope) {
                    // put watches here.
                    console.log("But not this. Why???"); // DOESN'T WORK!!
                    $scope.$eval($attributes.ngElementReady);
                };
            }
        };
    }]);

The console.log of the compile function works fine, but the returned link function still never gets executed.

Any idea why the link function might not get fired?

trusktr
  • 44,284
  • 53
  • 191
  • 263

1 Answers1

3

The error might be somewhere else. I tried it in a jsfiddle and the first version works.

eval()

In any case, you might have a missunderstanding about what $scope.$eval() does:

$scope.$eval() evaluates angularjs code against a scope. JavaScript's eval() function to run arbitrary js code in angularjs is $window.eval(). More about this here: Angular.js: How does $eval work and why is it different from vanilla eval?

I tested the directive isolated from the controller:

<div data-ng-element-ready="console.log('COMPILED!')"></div>

and the directive:

app.directive('ngElementReady', ['$window', function($window) {
return {
    restrict: "A",
    link: function($scope, $element, $attributes) {
        console.log("Reached the link fn", $attributes);
        $window.eval($attributes.ngElementReady);
    }
};
}]);

I do get the value "reached the link fn" and $attributes is correct:

Reached the link fn Object { $$element={...}, $attr={...},  
ngElementReady="console.log('COMPILED!')", more...}

And $window.eval() returns COMPILED!

and here with a controller.

in any case, using eval() to execute code written in an attribute looks dangerous. Anybody can modify the DOM to run code there. At least make sure that it won't affect any other users or server-side.

Reproducing the problem with ng-if

Edited after first comment: I tried making the ng-if expression evaluate to false here This time it doesn't show the message. This probably happens because in order to evaluate ng-if, yuo must compile first the directive. otherwise, it's just code that anuglarjs isn't aware of. However, because it is removed from the DOM, it never reaches the link function.

Execution order of AngularJS functions

In general, the order of execution goes like this (Josh David Miller explains it:

<div directive1>
  <div directive2>
    <!-- ... -->
  </div>
</div>

Now AngularJS will create the directives by running directive functions in a certain order:

directive1: compile
  directive2: compile
directive1: controller
directive1: pre-link
  directive2: controller
  directive2: pre-link
  directive2: post-link
directive1: post-link
Community
  • 1
  • 1
Eduard Gamonal
  • 8,023
  • 5
  • 41
  • 46
  • Thanks for the tip on eval. I won't use that aftwr all, but the console.log line which is before it sgould execute, even if the $eval doesn't work, right? I don't see why mine doesn't. The problem is I have tons of code so I can't really fiddle it. If i make a fiddle, it will probably work because it's so simple. I wonder in general what might cause a link function to be ignored. – trusktr May 18 '14 at 13:26
  • maybe you can start checking ng-if? normally you don't use ng-if and ng-show in the same directive, because ng-if removes the element from the DOM and ng-show just hides it. – Eduard Gamonal May 18 '14 at 13:35
  • hey @trusktr I edited my answer to give you some more hints. check the value of your `analysis.type` variable. maybe you can force it to be true and see what happens, or remove the `ng-if` attribute? – Eduard Gamonal May 18 '14 at 13:48
  • Thanks for the insight! You helped me find the problem: If the value of analysis.type used in the ngInclude directive doesn't cause a matching template to be found, then the link function of my ngElementReady directive doesn't execute. As soon as I set the value of analysis.type (at some time in the future) to some value that causes a template to be found, then I see the link function output. This is actually good, as it lets me run stuff when the "element ready". – trusktr May 19 '14 at 02:30