AngularJS: обратный вызов после рендера (работа с DOM после рендера)
Как можно запустить метод $scope.myWork()
после рендеринга шаблона? Я хочу установить $scope.value
и после этого мне нужно что-то изменить с помощью JQuery (например, в DOM содержимого шаблона). $scope.$watch('value', function (){....})
работает "до" рендера (DOM шаблона еще не доступен). Благодарю.
5 ответов
Я использую terminal
а также transclude
в директиве атрибута для вызова метода с областью действия после обновления модели и отображения (в моем случае изменение размера iframe после $Resource.query):
.directive('postRender', [ '$timeout', function($timeout) {
var def = {
restrict : 'A',
terminal : true,
transclude : true,
link : function(scope, element, attrs) {
$timeout(scope.resize, 0); //Calling a scoped method
}
};
return def;
}])
Таймаут $ - черная магия. Должна быть возможность объявить метод JS как значение атрибута и $parse it.
Так что я использую это в ng-repeat
(в моем случае дерево отображается рекурсивно):
<div post-render ng-repeat="r in regions | orderBy:'name'" ng-include="'tree_region_renderer.html'">
У меня также была эта проблема, другие решения не работали для меня, и казалось, что Protractor должен был решить эту проблему. Краткий обзор клиентских сценариев Protractor показывает, что он использует angular.getTestability(element)
знать, когда на самом деле запустить тесты. Метод ожидает, пока не будет отложенных таймаутов или http-запросов, а затем запускает обратный вызов. Вот моя директива:
export function afterRender ($timeout) {
"ngInject";
return {
restrict: 'A',
terminal: true,
link: function (scope, element, attrs) {
angular.getTestability(element).whenStable(function() {
console.log('[rendered]');
});
}
};
}
Ответ Jens выше будет работать, но обратите внимание, что в более новых версиях AngularJS (например, 1.2.3) эта директива postRender не может быть в сочетании с ng-repeat в качестве атрибутов одного и того же тега, поскольку они оба имеют transclude: true. В этом случае вы должны либо удалить transclude, либо иметь отдельный тег с атрибутом директивы postRender.
Также следует помнить о приоритете атрибутов при использовании терминала: истина, поскольку в конечном итоге атрибут может оказаться неэффективным из-за более высокого приоритета в том же теге.
Я нашел эту страницу, когда искал способ профилировать рендеринг DOM. Я нашел очень простое решение, которое работает для моего варианта использования.
Присоедините обработчик ng-init к элементу DOM и в функции обработчика используйте $timeout, чтобы завершить выполнение. Пример:
HTML:
<div ng-init="foo()">
JS:
$scope.foo = function() {
$timeout(function() {
// This code runs after the DOM renders
});
});