há um retorno de chamada post render para a diretiva Angular JS?

Acabei de obter minha diretiva para puxar um modelo para acrescentar ao seu elemento como este:

# CoffeeScript .directive 'dashboardTable', -> controller: lineItemIndexCtrl templateUrl: "" (scope, element, attrs) -> element.parent('table#line_items').dataTable() console.log 'Just to make sure this is run' # HTML 

Eu também estou usando um Plugin jQuery chamado DataTables. O uso geral é assim: $ (‘table # some_id’). DataTable (). Você pode passar os dados JSON para a chamada dataTable () para fornecer os dados da tabela OU você pode ter os dados já na página e eles farão o resto .. Eu estou fazendo o último, tendo as linhas já na página HTML .

Mas o problema é que eu tenho que chamar o dataTable () na tabela # line_items AFTER DOM pronto. Minha diretiva acima chama o método dataTable () ANTES de o modelo ser anexado ao elemento da diretiva. Existe uma maneira que eu possa chamar funções após o acréscimo?

Obrigado pela ajuda!

ATUALIZAÇÃO 1 após a resposta de Andy:

Eu quero ter certeza de que o método link só é chamado depois que tudo está na página, então eu alterei a diretiva para um pequeno teste:

 # CoffeeScript #angular.module(...) .directive 'dashboardTable', -> { link: (scope,element,attrs) -> console.log 'Just to make sure this gets run' element.find('#sayboo').html('boo') controller: lineItemIndexCtrl template: "
" }

E eu realmente vejo “boo” no div # sayboo.

Então eu tento minha chamada datatable jquery

 .directive 'dashboardTable', -> { link: (scope,element,attrs) -> console.log 'Just to make sure this gets run' element.parent('table').dataTable() # NEW LINE controller: lineItemIndexCtrl templateUrl: "" } 

Sem sorte ai

Então eu tento adicionar um tempo limite:

 .directive 'dashboardTable', ($timeout) -> { link: (scope,element,attrs) -> console.log 'Just to make sure this gets run' $timeout -> # NEW LINE element.parent('table').dataTable() ,5000 controller: lineItemIndexCtrl templateUrl: "" } 

E isso funciona. Então, eu me pergunto o que está errado na versão sem timer do código?

Se o segundo parâmetro, “atraso” não for fornecido, o comportamento padrão será executar a function após a conclusão da renderização do DOM. Então, ao invés de setTimeout, use $ timeout:

 $timeout(function () { //DOM has finished rendering }); 

Eu tive o mesmo problema e acredito que a resposta é realmente não. Veja o comentário de Miško e alguma discussão no grupo .

O Angular pode rastrear que todas as chamadas de function que ele faz para manipular o DOM estão completas, mas como essas funções podem acionar a lógica assíncrona que ainda está atualizando o DOM depois que elas retornam, não se pode esperar que Angular saiba disso. Qualquer retorno de chamada que o Angular forneça pode funcionar algumas vezes, mas não seria seguro confiar nele.

Nós resolvemos isso heuristicamente com um setTimeout, como você fez.

(Por favor, tenha em mente que nem todos concordam comigo – você deve ler os comentários nos links acima e ver o que você pensa.)

Embora minha resposta não esteja relacionada a dados, trata da questão da manipulação de DOM e, por exemplo, da boot de plugins do jQuery para diretivas usadas em elementos que têm seu conteúdo atualizado de maneira assíncrona.

Em vez de implementar um tempo limite, basta adicionar um relógio que escute as alterações de conteúdo (ou até mesmo gatilhos externos adicionais).

No meu caso eu usei esta solução alternativa para inicializar um plugin jQuery uma vez que o ng-repeat foi feito para criar o meu DOM interno – em outro caso eu usei apenas para manipular o DOM depois que a propriedade scope foi alterada no controller. Aqui está como eu fiz …

HTML:

 
{{myContent}}

JS:

 app.directive('myDirective', [ function(){ return { restrict : 'A', scope : { myDirectiveWatch : '=' }, compile : function(){ return { post : function(scope, element, attributes){ scope.$watch('myDirectiveWatch', function(newVal, oldVal){ if (newVal !== oldVal) { // Do stuff ... } }); } } } } }]); 

Nota: Em vez de apenas converter a variável myContent em bool no atributo my-directive-watch, poderíamos imaginar qualquer expressão arbitrária ali.

Nota: Isolar o escopo como no exemplo acima só pode ser feito uma vez por elemento – tentar fazer isso com várias diretivas no mesmo elemento resultará em um erro $ compile: multidir – veja: https://docs.angularjs.org / error / $ compile / multidir

Você pode usar a function ‘link’, também conhecida como postLink, que é executada depois que o modelo é inserido.

 app.directive('myDirective', function() { return { link: function(scope, elm, attrs) { /*I run after template is put in */ }, template: 'Hello' } }); 

Dê uma lida se você planeja fazer diretivas, é uma grande ajuda: http://docs.angularjs.org/guide/directive

Pode ser tarde para responder a esta pergunta. Mas ainda assim alguém pode se beneficiar da minha resposta.

Eu tive problema semelhante e no meu caso eu não posso mudar a diretiva, pois, é uma biblioteca e alterar um código da biblioteca não é uma boa prática. Então, o que eu fiz foi usar uma variável para esperar o carregamento da página e usar ng-if dentro do meu html para esperar renderizar o elemento em particular.

No meu controlador:

 $scope.render=false; //this will fire after load the the page angular.element(document).ready(function() { $scope.render=true; }); 

No meu html (no meu caso, o componente html é uma canvas)

   

Eu tive o mesmo problema, mas usando Angular + DataTable com um fnDrawCallback + agrupando linha + $ fnDrawCallback nesteds compilados. Eu coloquei o timeout $ na minha function fnDrawCallback para corrigir a renderização de paginação.

Antes exemplo, com base na fonte row_grouping:

 var myDrawCallback = function myDrawCallbackFn(oSettings){ var nTrs = $('table#result>tbody>tr'); for(var i=0; i 

Depois do exemplo:

 var myDrawCallback = function myDrawCallbackFn(oSettings){ var nTrs = $('table#result>tbody>tr'); $timeout(function requiredRenderTimeoutDelay(){ for(var i=0; i 

Até mesmo um curto intervalo de tempo foi suficiente para permitir que o Angular processasse minhas diretivas Angulares compiladas.

Nenhuma das soluções funcionou para mim aceitar usando um tempo limite. Isso ocorre porque eu estava usando um modelo que estava sendo criado dinamicamente durante o postLink.

Observe, no entanto, que pode haver um tempo limite de ‘0’, já que o tempo limite adiciona a function sendo chamada à fila do navegador, que ocorrerá após o mecanismo de renderização angular, já que isso já está na fila.

Consulte: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering

Aqui está uma diretiva para ter ações programadas após uma renderização superficial. Por superficial quero dizer que irá avaliar depois que muito elemento processado e que não será relacionado a quando o seu conteúdo é processado. Então, se você precisar de algum sub-elemento fazendo uma ação post render, considere usá-lo lá:

 define(['angular'], function (angular) { 'use strict'; return angular.module('app.common.after-render', []) .directive('afterRender', [ '$timeout', function($timeout) { var def = { restrict : 'A', terminal : true, transclude : false, link : function(scope, element, attrs) { if (attrs) { scope.$eval(attrs.afterRender) } scope.$emit('onAfterRender') } }; return def; }]); }); 

então você pode fazer:

ou com qualquer expressão útil como:

Eu tenho esse trabalho com a seguinte diretiva:

 app.directive('datatableSetup', function () { return { link: function (scope, elm, attrs) { elm.dataTable(); } } }); 

E no HTML:

 

resolução de problemas se o acima não funcionar para você.

1) observe que ‘datatableSetup’ é o equivalente de ‘datatable-setup’. Angular muda o formato para o caso do camelo.

2) certifique-se de que o aplicativo esteja definido antes da diretiva. por exemplo, definição de aplicativo simples e diretiva.

 var app = angular.module('app', []); app.directive('datatableSetup', function () { return { link: function (scope, elm, attrs) { elm.dataTable(); } } }); 

Seguindo o fato de que a ordem de carga não pode ser antecipada, uma solução simples pode ser usada.

Vamos dar uma olhada no relacionamento diretivo – ‘usuário de diretiva’. Normalmente, o usuário da diretiva fornecerá alguns dados à diretiva ou usará algumas funcionalidades (funções) que a diretiva fornece. A diretiva, por outro lado, espera que algumas variables ​​sejam definidas em seu escopo.

Se pudermos garantir que todos os jogadores tenham todos os seus requisitos de ação cumpridos antes de tentar executar essas ações – tudo deve estar bem.

E agora a diretiva:

 app.directive('aDirective', function () { return { scope: { input: '=', control: '=' }, link: function (scope, element) { function functionThatNeedsInput(){ //use scope.input here } if ( scope.input){ //We already have input functionThatNeedsInput(); } else { scope.control.init = functionThatNeedsInput; } } }; }) 

e agora o usuário da diretiva html

  

e em algum lugar no controlador do componente que usa a diretiva:

 $scope.control = {}; ... $scope.input = 'some data could be async'; if ( $scope.control.functionThatNeedsInput){ $scope.control.functionThatNeedsInput(); } 

É sobre isso. Há muita sobrecarga, mas você pode perder o tempo limite de $. Também assumimos que o componente que usa a diretiva é instanciado antes da diretiva porque dependemos da variável de controle para existir quando a diretiva é instanciada.