yedpodtrzitko
yedpodtrzitko

Reputation: 9359

access to ng-included DOM nodes?

My first experiment with angular.js.

I've a few columns, each of them includes some template:

<div class="col-md-5 js-column" ng-repeat="orm in orms" repeat-done="equalHeight">
    <h2>{{ orm.name }}</h2>
    <ng-include src="'/inc/_compiled/'+orm.id+'.html'"></ng-include>
</div>

Each included template contains the same elements as other templates, but they've different height. Example element:

<pre data-task="model" class="task-model">
from django.db import models
class Teacher(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

</pre>

The thing I want to achieve is to set equal height for specific element in all the columns. That means all pre.task-model will have the same height.

I've created some directive and the idea was to trigger it after ngRepeat loop is finished (scope.$last). But when I try to access the included nodes via jQuery/DOM selectors, I get nothing. I know each template is available in element variable, but I need to get also the other columns.

var ormApp = angular
    .module('ormApp', [])
    .directive('repeatDone', function () {
        return function (scope, element, attrs) {
            if (scope.$last) {
                $('.js-column pre.task-model'); //<- got nothing
            }
        };
    })

Upvotes: 0

Views: 86

Answers (1)

gkalpak
gkalpak

Reputation: 48211

As mentioned in the comments, using $timeout solves the problem.
But why ?

The issue here is that several operations involved in the process, such as creating a new element (by ngRepeat), fetching the template (by ngInclude) using $http.get() (even if it comes from the $templateCache), resolving the promises returned etc, are asynchronously and are handled using $evalAsync(), which means that they are going to "happen" when everything else currently on Angular's async queue is processed.

Since there are several levels of nested $evalAsyncs (in this particular case 7), you can achieve what you want by iteratively calling $evalAsync() until the async operations required for fetching and lining the template are completed.

This is of course not a robust (or recommended) way to solve the problem, it is just meant to explain what is going on. Using $timeout puts the operation in the browser's event queue, so the command will be processed after Angular's current $digest loop is completed (i.e. after all tasks on Angular's async queue have been processed and all taks added to the queue by those async taks etc).
(Another side-effect here is that, since the rendering engine's "render" command is already on the browser event queue, using $timeout will execute the command after the next DOM rendering has taken place. This has no relevance for this particular case, but might be important in other situations.)


See, also, this short demo illustrating both aproaches (open the DevTools console).

Upvotes: 1

Related Questions