AngularJS directive runs before element is fully loaded

▼魔方 西西 提交于 2019-12-08 15:13:16

问题


I have a directive attached to a dynamically generated <table> element inside a template. The directive manipulates the DOM of that table inside a link function. The problem is that the directive runs before the table is rendered (by evaluating ng-repeat directives) - the table is empty then.

Question

How can I make sure that the directive is ran after the table has been fully rendered?

<table directive-name>
    <tr ng-repeat="...">
        <td ng-repeat="..."></td>
    </tr>
</table>


module.directive("directiveName", function() {
    return {
        scope: "A",
        link: function(scope, element, attributes) {
            /* I need to be sure that the table is already fully
               rendered when this code runs */
        }
    };
});

回答1:


You can't, in a general sense, be ever "fully sure" by just having a directive on the <table> element.

But you can be sure in certain cases. In your case, if the inner content is ng-repeat-ed, then if the array of items over which ngRepeat works is ready, then the actual DOM elements will be ready at the end of the digest cycle. You can capture it after $timeout with 0 delay:

link: function(scope, element){
  $timeout(function(){
    console.log(element.find("tr").length); // will be > 0
  })
}

But, in a general sense, you can't be certain to capture the contents. What if the ngRepeated array is not there yet? Or what if there is an ng-include instead?

<table directive-name ng-include="'templates/tr.html'">
</table>

Or, what if there was a custom directive that worked differently than ngRepeat does?

But if you have full control of the contents, one possible way to know is to include some helper directive as the innermost/last element, and have it contact its parent directiveName when it's linked:

<table directive-name>
    <tr ng-repeat="...">
        <td ng-repeat="...">
          <directive-name-helper ng-if="$last">
        </td>
    </tr>
</table>
.directive("directiveNameHelper", function(){
  return {
    require: "?^directiveName",
    link: function(scope, element, attrs, ctrl){
      if (!ctrl) return;

      ctrl.notifyDone();
    }
  }
})



回答2:


Try wrapping in a $timeout the code from your link function as it will execute after the DOM is rendered.

$timeout(function () {
    //do your stuff here as the DOM has finished rendering already
});

Don't forget to inject $timeout in your directive:

.directive("directiveName", function($timeout) {

There are plenty of alternatives but I think this one is cleaner as the $timeout executes after the rendering engine has finished its job.




回答3:


A clean way would be to use something like lodash's _.defer method.

You can call it with _.defer(your_func, your_func_arg1, your_func_arg2, ...) inside your link to execute the method, when the current call stack has cleared and everything is ready.

This way, you don't have to estimate a $timeout by yourself.



来源:https://stackoverflow.com/questions/32074053/angularjs-directive-runs-before-element-is-fully-loaded

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!