Como posso executar uma diretiva depois que o dom terminar de renderizar?

Eu tenho um problema aparentemente simples, sem solução aparente (lendo o JS Angular) .

Eu tenho uma diretiva Angular JS que faz alguns cálculos com base na altura de outros elementos DOM para definir a altura de um contêiner no DOM.

Algo semelhante a isso está acontecendo dentro da diretiva:

return function(scope, element, attrs) { $('.main').height( $('.site-header').height() - $('.site-footer').height() ); } 

A questão é que quando a diretiva é executada, $('site-header') não pode ser encontrado, retornando uma matriz vazia em vez do elemento DOM embrulhado em jQuery que eu preciso.

Existe um retorno de chamada que eu possa usar dentro da minha diretiva que só é executado depois que o DOM foi carregado e eu posso acessar outros elementos DOM através das consultas normais do estilo do seletor jQuery?

Depende de como seu $ (‘site-header’) é construído.

Você pode tentar usar $ timeout com 0 delay. Algo como:

 return function(scope, element, attrs) { $timeout(function(){ $('.main').height( $('.site-header').height() - $('.site-footer').height() ); }); } 

Explicações sobre como isso funciona: um , dois .

Não esqueça de injetar $timeout na sua diretiva:

 .directive('sticky', function($timeout) 

Aqui está como eu faço:

 app.directive('example', function() { return function(scope, element, attrs) { angular.element(document).ready(function() { //MANIPULATE THE DOM }); }; }); 

Provavelmente o autor não precisará mais da minha resposta. Ainda assim, por uma questão de perfeição, sinto que outros usuários podem achar útil. A melhor e mais simples solução é usar $(window).load() dentro do corpo da function retornada. (alternativamente você pode usar document.ready . Isso realmente depende se você precisa de todas as imagens ou não).

Usar $timeout na minha humilde opinião é uma opção muito fraca e pode falhar em alguns casos.

Aqui está o código completo que eu usaria:

 .directive('directiveExample', function(){ return { restrict: 'A', link: function($scope, $elem, attrs){ $(window).load(function() { //...JS here... }); } } }); 

existe um evento ngcontentloaded , eu acho que você pode usá-lo

 .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) } } }); 

Se você não pode usar $ timeout devido a resources externos e não pode usar uma diretiva devido a um problema específico com o tempo, use broadcast.

Adicione $scope.$broadcast("variable_name_here"); depois que o recurso externo desejado ou a diretiva / controlador de longa execução for concluída.

Em seguida, adicione o abaixo depois que seu recurso externo for carregado.

 $scope.$on("variable_name_here", function(){ // DOM manipulation here jQuery('selector').height(); } 

Por exemplo, na promise de uma solicitação HTTP adiada.

 MyHttpService.then(function(data){ $scope.MyHttpReturnedImage = data.image; $scope.$broadcast("imageLoaded"); }); $scope.$on("imageLoaded", function(){ jQuery('img').height(80).width(80); } 

Eu tive um problema parecido e quero compartilhar minha solução aqui.

Eu tenho o seguinte HTML:

 

Problema: Na function de link da diretiva do pai div eu queria jquery’ing o filho div # sub. Mas apenas me deu um object vazio porque ng-include não tinha terminado quando a function de link da diretiva funcionava. Então, primeiro eu fiz uma solução suja com $ timeout, que funcionou, mas o delay-parameter dependia da velocidade do cliente (ninguém gosta disso).

Funciona, mas sujo:

 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; }]); 

Aqui está a solução limpa:

 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; }]); 

Talvez isso ajude alguém.