Как я могу запустить директиву после того, как dom закончил рендеринг?
У меня есть кажущаяся простая проблема без видимых (прочитав решение Angular JS docs).
У меня есть директива J5 Angular, которая выполняет некоторые вычисления, основанные на высоте других элементов DOM, чтобы определить высоту контейнера в DOM.
Что-то похожее на это происходит внутри директивы:
return function(scope, element, attrs) {
$('.main').height( $('.site-header').height() - $('.site-footer').height() );
}
Проблема в том, что при запуске директивы $('site-header')
не может быть найден, возвращая пустой массив вместо связанного с jQuery элемента DOM, который мне нужен.
Есть ли обратная связь, которую я могу использовать в моей директиве, которая запускается только после загрузки DOM, и я могу получить доступ к другим элементам DOM через обычные запросы стиля селектора jQuery?
Ответы
Ответ 1
Это зависит от того, как сконфигурирован ваш $('site-header').
Вы можете попытаться использовать $timeout с задержкой 0. Что-то вроде:
return function(scope, element, attrs) {
$timeout(function(){
$('.main').height( $('.site-header').height() - $('.site-footer').height() );
});
}
Объяснения, как это работает: один, два.
Не забудьте ввести $timeout
в свою директиву:
.directive('sticky', function($timeout)
Ответ 2
Вероятно, автору больше не понадобится мой ответ. Тем не менее, для полноты я чувствую, что другие пользователи могут оказаться полезными. Лучшее и самое простое решение - использовать $(window).load()
внутри тела возвращаемой функции. (альтернативно вы можете использовать document.ready
. Это действительно зависит, нужны ли вам все изображения или нет).
Использование $timeout
по моему скромному мнению является очень слабым вариантом и может быть неудачным в некоторых случаях.
Вот полный код, который я бы использовал:
.directive('directiveExample', function(){
return {
restrict: 'A',
link: function($scope, $elem, attrs){
$(window).load(function() {
//...JS here...
});
}
}
});
Ответ 3
Вот как я это делаю:
app.directive('example', function() {
return function(scope, element, attrs) {
angular.element(document).ready(function() {
//MANIPULATE THE DOM
});
};
});
Ответ 4
есть событие ngcontentloaded
, я думаю, вы можете его использовать
.directive('directiveExample', function(){
return {
restrict: 'A',
link: function(scope, elem, attrs){
$$window = $ $window
init = function(){
contentHeight = elem.outerHeight()
//do the things
}
$$window.on('ngcontentloaded',init)
}
}
});
Ответ 5
Если вы не можете использовать $timeout из-за внешних ресурсов и не можете использовать директиву из-за определенной проблемы с синхронизацией, используйте широковещательную передачу.
Добавьте $scope.$broadcast("variable_name_here");
после того, как завершится требуемый внешний ресурс или длинный контроллер/директива.
Затем добавьте ниже после загрузки внешнего ресурса.
$scope.$on("variable_name_here", function(){
// DOM manipulation here
jQuery('selector').height();
}
Например, в обещании отложенного HTTP-запроса.
MyHttpService.then(function(data){
$scope.MyHttpReturnedImage = data.image;
$scope.$broadcast("imageLoaded");
});
$scope.$on("imageLoaded", function(){
jQuery('img').height(80).width(80);
}
Ответ 6
У меня была аналогичная проблема и я хочу поделиться своим решением здесь.
У меня есть следующий HTML:
<div data-my-directive>
<div id='sub' ng-include='includedFile.htm'></div>
</div>
Проблема: в link-function директивы родительского div я хотел jquery'ing дочернего div # sub. Но он просто дал мне пустой объект, потому что ng-include еще не закончил работу с функцией ссылки. Поэтому сначала я сделал грязное обходное решение с $timeout, которое работало, но параметр задержки зависел от скорости клиента (ему это не нравится).
Работает, но грязно:
app.directive('myDirective', [function () {
var directive = {};
directive.link = function (scope, element, attrs) {
$timeout(function() {
//very dirty cause of client-depending varying delay time
$('#sub').css(/*whatever*/);
}, 350);
};
return directive;
}]);
Здесь чистое решение:
app.directive('myDirective', [function () {
var directive = {};
directive.link = function (scope, element, attrs) {
scope.$on('$includeContentLoaded', function() {
//just happens in the moment when ng-included finished
$('#sub').css(/*whatever*/);
};
};
return directive;
}]);
Может быть, это помогает кому-то.