Is $timeout still best practice for waiting on Angular directive template?
Asked Answered
T

1

8

Our team's design pattern for waiting on a directive's template to render is to wrap our DOM manipulation code in a $timeout (inside the directive's link function), which I know at one time was the normal design pattern. Is that still true, or are there better/safer design patterns to do this?

Example of pattern is in ECMAScript6:

link: ($scope, $element) => {
  $timeout(() => {
     var domElementFromTemplate = $element.find('myDOMElement');
  } 
}
Travertine answered 16/3, 2017 at 13:23 Comment(6)
It's been a long time to be honest... We've been using AngularJS for about 2 years, so it would have been something I read back then.Travertine
Please give me a link.Radioman
#12241139 There's one.Travertine
#11125578 And another.Travertine
It's not a best practice but it's a valid option to wait for some bindings to be executed. For example, when using a ng-if. This way, you can execute code once the HTML has been injected in your page. $timeout just add a function in the event loop task queue.Boschbok
I'm going to give a few of the suggestions a try on Monday. I was unaware a document ready would fire more than once on a single page app, so that solution makes me curious. ;)Travertine
R
4

While you try to select an element which is available in DOM:

It never been a best practise IMO because there is no need to create an asynchronous behavior to an synchronous dom select function. Due to the angular.element documentation it should look like this:

link: ($scope, $element) => {
    var domElementFromTemplate = $element.find('myDOMElement');
}

While you try to select an element which is supposed to be rendered in your directive:

The timeout function should avoid DOM-rendering async behavior but IMO there are a lot more better approaches to deal with this issue:


Solution 1)

An other approach is to get the document ready state to ensure you element is available in DOM like:

link: ($scope, $element) => {
    angular.element(document).ready(() => {
        var domElementFromTemplate = $element.find('myDOMElement');
    });
}

Solution 2)

An other approach is to create an other directive for those elements, which were rendered inside a directive, e.g. (myDOMElement) to avoid DOM injection at all.

link: ($scope, $element) => {},
template: "<div some-other-child-directive></div>"

Solution 3)

It should be a much better and more neat approach to create a callback function to ensure the element is available in DOM. This could be done by ng-init="someCallback()" to start up your element functionalities.


Solution 4)

Yes, using $timeout still works fine while a new $timeout will be added to the to the execution queue and will be executed after the DOM was rendered. A timeout delay value is not needed.

link: ($scope, $element) => {
    $timeout(() => {
        var domElementFromTemplate = $element.find('myDOMElement');
    }
}
Radioman answered 16/3, 2017 at 13:27 Comment(1)
I know that doesn't work. If the DOM element is in your directive's template. It may work sometimes on fast machines when hosted locally.Travertine

© 2022 - 2024 — McMap. All rights reserved.