Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

Directive allocation inside a parent template:

<div badge></div>

Directive template templates/badge.html:
Notice allocation of the dynamic id, using directive $id.

<div>
    <span id="id{{ ::$id }}_name">Nik Sumeiko, Frontend engineer</span>
</div>

Directive:

angular.module('app').directive('badge', () => ({
  restrict: "A",
  replace: true,
  templateUrl: "templates/badge.html",
  link: (scope, element, attributes) => {

    // Tries to query nested DOM element by a dynamic selector.
    const name = element.find(`#id${scope.$id}_name`);

    console.log(name.length, element.html());
  }
}));

Based on the console output it's clearly visible that directive template haven't compiled its dynamic values yet:

0 "
    <div>
      <span id="id{{ ::$id }}_name">Nik Sumeiko, Frontend engineer</span>
    </div>
"

How then it is possible to query nested elements by a dynamic selector? Is there any other directive methods that are dispatched after Angular rendered dynamic values of the template?

Please don't suggest to use $timeout injected function to delay template rendering inside link method, since I don't think it is the right way…

share|improve this question

Here the quote from angular documentation:

After linking the view is not updated until after a call to $digest which typically is done by Angular automatically.

That's why you can't find the elements containing expressions in their id - the view is not updated at that time.

Here the workarounds:

Create the element and attach it to the DOM manually

This way you have a reference to element, so you don't have to query for it:

link: (scope, element, attributes) => {
    let span = $compile('<span id="id{{ ::$id }}_name">Nik Sumeiko, Frontend engineer</span>')(scope);
    // do something to span ...
    element.append(span);
}

Use $timeout

You can use $timeout with a zero delay, it is not the wrong way. $timeout will execute your code right after the current $digest cycle, meaning after the view bindings are updated:

link: (scope, element, attributes) => {
    $timeout(function() {
        let span = element[0].querySelector(`#id${scope.$id}_name`);
    });
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.