Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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');
  } 
}
like image 996
Joe Firebaugh Avatar asked Mar 16 '17 13:03

Joe Firebaugh


1 Answers

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');
    }
}
like image 88
lin Avatar answered Nov 12 '22 03:11

lin