2015-08-18 4 views
10

У меня есть директива, прикрепленная к динамически генерируемому элементу <table> внутри шаблона. Директива управляет DOM этой таблицы внутри функции link. Проблема в том, что директива выполняется до отображения таблицы (путем оценки директив ng-repeat) - тогда таблица пуста.Директива AngularJS работает до того, как элемент полностью загружен

Вопрос

Как я могу убедиться, что директива побежал после того, как таблица была полностью оказана?

<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

Вы можете добавить ng-if в тег таблицы и условие может быть при загрузке данных таблицы. – Hmahwish

+0

- это ваши данные, поступающие из запроса '$ http' или только жестко закодированные данные. –

+0

@K.Toress Data поступает из HTTP-запроса, но уже загружается при обработке этого шаблона - маршрутизация и контроллер заботятся об этом, используя атрибут 'resolve' в конфигурации' $ routeProvider'. –

ответ

4

Вы не можете в общем смысле быть «полностью уверенным», просто указав на элемент <table>.

Но вы можете быть уверены в некоторых случаях. В вашем случае, если внутренний контент ng-repeat -ed, то если массив элементов, над которыми работает ngRepeat, готов, то фактические элементы DOM будут готовы в конце цикла дайджеста. Вы можете захватить его после $timeout с 0 задержкой:

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

Но, в общем смысле, вы не можете быть уверены, чтобы захватить содержимое. Что делать, если массив ngRepeat еще не существует? Или что, если вместо этого есть ng-include?

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

Или, что если есть пользовательские директивы, которые работали по-другому, чем ngRepeat делает?

Но если у вас есть полный контроль над содержимым, один из возможных способов знать, чтобы включить некоторые вспомогательные директивы в качестве внутреннего/последнего элемента, и он связаться с его родителем directiveName, когда это связано:

<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

Это самый полный ответ здесь, я думаю. Благодарю. Я до сих пор не понимаю, почему '$ timeout' с 0 задержкой гарантирует, что DOM будет готов, но я думаю, что найду это в документах Angle's $ timeout. –

+1

@Robert, 'ng-repeat' имеет' $ scope. $ WatchCollection' - это срабатывает после фазы ссылки, и если массив готов, то он переводит шаблон 'ng-repeat'-ed и помещает его в DOM. '$ timeout' с 0 задержкой выполняется сразу после этого –

2

Try обертывание в $timeout код из вашей функции связи, как он будет выполнять после того, как DOM визуализируется.

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

Не забудьте вводить $timeout в вашей директиве:

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

Есть много альтернатив, но я думаю, что это один чище, как $ таймаут выполняется после того, как движок рендеринга завершил свою работу ,

0

Чистым способом было бы использовать что-то вроде lodash's _.defer method.

Вы можете позвонить ему с помощью _.defer(your_func, your_func_arg1, your_func_arg2, ...) внутри вашей ссылки, чтобы выполнить метод, когда текущий стек вызовов очищен и все готово.

Таким образом, вы не должны оценивать $timeout самостоятельно.

+0

' _.defer' просто вызывает 'setTimout' без задержки, хотя он выполняет некоторые проверки времени выполнения параметров, которые вы проходите. Если вы уже не используете lodash, вы может также использовать NG, встроенный в '$ timeout', без задержки. – jusopi

+0

Не знал этого, спасибо! –

Смежные вопросы