Henri Korpela
Henri Korpela

Reputation: 111

AngularJS - Why can't I access child elements in link-function?

I was messing around with AngularJS in order to create a custom component system. I have asked a question regarding my component system already here, so you can check it out in order to understand how my system ought to work (perhaps it has changed a little, but the basic idea remains the same).

I have tried to look for a child element through the component directive and ng-include-attributed element, but somehow things aren't working right.

Directive

My directive is as follows:

.directive("raqComponent", ["ComponentsStyles",
function(componentsStyles){
    return {
        restrict: "E",
        scope: {
            name: "@"
        },
        template: "<div ng-include=\"'/Components/' + name + '.htm'\"></div>",
        controller: function($scope, $timeout){
            componentsStyles.stylesheets.push($scope.name);

            if(components[$scope.name] !== undefined){
                if(components[$scope.name].getData !== undefined){
                    components[$scope.name].getData($scope);
                }
            }
        },
        link: function(scope, elem, attrs){
            if(components[scope.name] !== undefined){
                if(components[scope.name].link !== undefined){
                    console.log("Children:", elem.children());
                    var elemTarget = elem;
                    components[scope.name].link(elemTarget);
                }
            }
        }
    };
}])

In this directive, which is used for each component, I use ng-include directive to include markup for my beloved components. Components are implemented in separate files in order to increase modularity.

Once the page has used component, DOM looks like this on the actual page:

enter image description here

Now, element raq-component has a child element with attribute ng-include. This element then has a child element, which is the root element of custom markup for a specific component. Like this:

<div class="navbar">
    <div class="container">
        <div class="row">
            <div class="col-md-12">
                <div class="navbar-items-container">
                    <div class="navbar-items">
                        <div ng-repeat="item in items" class="navbar-item">
                            <p>{{item.name}}</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

However, when I try to access child elements, I can't do that. I printed child elements in the directive like this:

if(components[scope.name].link !== undefined){
    console.log("Children:", elem.children());
    var elemTarget = elem;
    components[scope.name].link(elemTarget);
}

And children look like this:

enter image description here

Except there are none, for some reason! But why is that? I have used JQuery with functions like first(), last() and eq(0), but they don't do a thing. What's wierd is that I can see the children using Javascript without JQuery though:

enter image description here

So why can't I access child elements in link-function?

Upvotes: 1

Views: 860

Answers (1)

MMhunter
MMhunter

Reputation: 1441

The link function is in fact a post-link function that will be executed when child elements get compiled and linked.

However, from angular's official document:

Note that child elements that contain templateUrl directives will not have been compiled and linked since they are waiting for their template to load asynchronously and their own compilation and linking has been suspended until that occurs.

Though it didn't tell, the directive ngInclude is just like setting the templateUrl, and its template request is asynchronous.

This means by the time link function is called, the ngInclude has not got prepared for DOM manipulating. And u could not get the child elements.

Quick Solution:

Put the code in $scope.evalAsync and it will be executed after the directive's DOM manipulating.

Upvotes: 2

Related Questions