0

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…

1 Answer 1

2

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`);
    });
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.