Как я могу запустить директиву после того, как 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;
}]);

Может быть, это помогает кому-то.