existe-t-il un rappel post-rendu pour la directive Angular JS?

Je viens juste de recevoir ma directive pour insérer un modèle à append à son élément comme ceci:

# 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 

J’utilise aussi un plugin jQuery appelé DataTables. Son utilisation générale est la suivante: $ (‘table # some_id’). DataTable (). Vous pouvez transmettre les données JSON dans l’appel dataTable () pour fournir les données de la table OU vous pouvez déjà avoir les données sur la page et cela fera le rest. Je suis en train de faire ce dernier en ayant les lignes déjà sur la page HTML .

Mais le problème est que je dois appeler le dataTable () sur la table # line_items AFTER DOM ready. Ma directive ci-dessus appelle la méthode dataTable () AVANT que le modèle ne soit ajouté à l’élément de la directive. Existe-t-il un moyen d’appeler des fonctions APRÈS l’ajout?

Merci de votre aide!

MISE À JOUR 1 après la réponse d’Andy:

Je veux m’assurer que la méthode de liaison ne soit appelée qu’après tout, alors j’ai modifié la directive pour un petit test:

 # 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: "
" }

Et je vois en effet “boo” dans la div # sayboo.

Alors j’essaie mon appel jquery datatable

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

Pas de chance là-bas

Ensuite, j’essaie d’append un temps mort:

 .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: "" } 

Et ça marche. Donc, je me demande ce qui ne va pas dans la version non-timer du code?

Si le second paramètre, “delay” n’est pas fourni, le comportement par défaut consiste à exécuter la fonction une fois le rendu du DOM terminé. Donc, au lieu de setTimeout, utilisez $ timeout:

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

J’ai eu le même problème et je crois que la réponse est vraiment non. Voir le commentaire de Miško et quelques discussions dans le groupe .

Angular peut suivre que tous les appels de fonctions qu’il fait pour manipuler le DOM sont complets, mais comme ces fonctions peuvent déclencher une logique asynchrone qui met encore à jour le DOM après leur retour, on ne pouvait pas s’attendre à ce que Angular le sache. Tout rappel donné par Angular peut parfois fonctionner, mais il ne serait pas sûr de s’y fier.

Nous avons résolu ce problème de manière heuristique avec setTimeout, comme vous l’avez fait.

(Veuillez garder à l’esprit que tout le monde n’est pas d’accord avec moi – vous devriez lire les commentaires sur les liens ci-dessus et voir ce que vous en pensez).

Bien que ma réponse ne soit pas liée aux données, elle aborde la question de la manipulation du DOM et, par exemple, l’initialisation du plug-in jQuery pour les directives utilisées sur des éléments dont le contenu est mis à jour de manière asynchrone.

Au lieu de mettre en place un délai d’attente, il suffit d’append une montre pour écouter les modifications de contenu (ou même des déclencheurs externes supplémentaires).

Dans mon cas, j’ai utilisé cette solution pour initialiser un plugin jQuery une fois le ng-repeat terminé, ce qui a créé mon DOM interne. Dans un autre cas, je l’ai utilisé pour manipuler le DOM après que la propriété scope a été modifiée au contrôleur. Voici comment j’ai fait …

HTML:

 
{{myContent}}

JS:

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

Note: Au lieu de simplement placer la variable myContent sur bool dans l’atsortingbut my-directive-watch, on pourrait imaginer une expression arbitraire.

Remarque: L’ isolement de la scope comme dans l’exemple ci-dessus ne peut être effectué qu’une fois par élément. Si vous essayez de le faire avec plusieurs directives sur le même élément, vous obtiendrez une erreur $ comstack: multidir – voir: https://docs.angularjs.org / error / $ comstack / multidir

Vous pouvez utiliser la fonction ‘link’, également appelée postLink, qui s’exécute après la mise en place du modèle.

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

Lisez ceci si vous prévoyez de faire des directives, c’est une grande aide: http://docs.angularjs.org/guide/directive

Je peux être en retard pour répondre à cette question. Mais encore, quelqu’un peut tirer des bénéfices de ma réponse.

J’ai eu un problème similaire et dans mon cas, je ne peux pas changer la directive car, c’est une bibliothèque et changer un code de la bibliothèque n’est pas une bonne pratique. Donc, j’ai utilisé une variable pour attendre le chargement de la page et utiliser ng-if dans mon fichier HTML pour attendre le rendu de l’élément.

Dans mon contrôleur:

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

Dans mon html (dans mon cas le composant html est un canevas)

   

J’avais le même problème, mais en utilisant Angular + DataTable avec un regroupement de lignes fnDrawCallback + $ compilé des directives nestedes. J’ai placé $ timeout dans ma fonction fnDrawCallback pour corriger le rendu de la pagination.

Avant exemple, basé sur la source row_grouping:

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

Après exemple:

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

Même un court délai d'attente était suffisant pour permettre à Angular de rendre mes directives angulars compilées.

Aucune des solutions mises en œuvre pour moi n’accepte d’utiliser un délai d’attente. C’est parce que j’utilisais un modèle qui était créé dynamicment pendant le postLink.

Notez toutefois qu’il peut y avoir un délai d’attente de «0» car le délai d’attente ajoute la fonction appelée à la queue du navigateur, laquelle se produit après le moteur de rendu angular, car il se trouve déjà dans la queue.

Référez-vous à ceci: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-fin-rendering

Voici une directive pour avoir des actions programmées après un rendu superficiel. Par faible profondeur, je veux dire qu’il va évaluer après cet élément rendu et qui ne sera pas lié au rendu de son contenu. Donc, si vous avez besoin d’un sous-élément pour effectuer une action de post-rendu, vous devriez envisager de l’utiliser ici:

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

alors vous pouvez faire:

ou avec toute expression utile comme:

Je travaille avec la directive suivante:

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

Et dans le HTML:

 

dépannage si ce qui précède ne fonctionne pas pour vous.

1) notez que ‘datatableSetup’ est l’équivalent de ‘datatable-setup’. Angular change le format en cas camel.

2) assurez-vous que l’application est définie avant la directive. Par exemple, définition et directive simples de l’application.

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

Si l’on ne peut pas anticiper l’ordre de chargement, une solution simple peut être utilisée.

Regardons la relation directive-‘user de directive ‘. Habituellement, l’utilisateur de la directive fournira certaines données à la directive ou utilisera certaines fonctionnalités (fonctions) des fournitures de la directive. La directive, quant à elle, attend que certaines variables soient définies sur son périmètre.

Si nous pouvons nous assurer que tous les joueurs ont satisfait à toutes leurs exigences avant d’essayer d’exécuter ces actions, tout devrait bien se passer.

Et maintenant la directive:

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

et maintenant l’utilisateur de la directive html

  

et quelque part dans le contrôleur du composant qui utilise la directive:

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

C’est à peu près ça. Il y a beaucoup de surcharge mais vous pouvez perdre le timeout $. Nous supposons également que le composant qui utilise la directive est instancié avant la directive car nous dépendons de la variable de contrôle pour exister lorsque la directive est instanciée.