Je viens de recevoir ma directive pour insérer un modèle à ajouter à son élément comme ceci:
# CoffeeScript
.directive 'dashboardTable', ->
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
(scope, element, attrs) ->
element.parent('table#line_items').dataTable()
console.log 'Just to make sure this is run'
# HTML
<table id="line_items">
<tbody dashboard-table>
</tbody>
</table>
J'utilise également un plugin jQuery appelé DataTables. Son utilisation générale est la suivante: $ ('table # some_id'). DataTable (). Vous pouvez passer les données JSON dans l'appel dataTable () pour fournir les données de la table OU vous pouvez avoir les données déjà sur la page et il fera le reste .. Je fais ce dernier, 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 APRÈS DOM prêt. 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 lien n'est appelée qu'APRÈS que tout est sur la page, j'ai donc 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: "<div id='sayboo'></div>"
}
Et je vois effectivement "boo" dans le div # sayboo.
Ensuite, j'essaye 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: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
}
Pas de chance là-bas
Ensuite, j'essaye d'ajouter 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: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
}
Et ça marche. Je me demande donc ce qui ne va pas dans la version sans minuterie du code?
Réponses:
Si le deuxième paramètre, "delay" n'est pas fourni, le comportement par défaut est d'exécuter la fonction une fois que le DOM a terminé le rendu. Donc, au lieu de setTimeout, utilisez $ timeout:
la source
$timeout(fn)
finalement,setTimeout(fn, 0)
ce qui a pour effet d'interrompre l'exécution de Javascript et de permettre au navigateur de rendre le contenu en premier, avant de continuer l'exécution de ce Javascript.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 fonction qu'il effectue pour manipuler le DOM sont terminés, mais comme ces fonctions pourraient déclencher une logique asynchrone qui met toujours à jour le DOM après leur retour, Angular ne pouvait pas s'attendre à le savoir. 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 un 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.)
la source
Vous pouvez utiliser la fonction «lien», également appelée postLink, qui s'exécute après l'insertion du modèle.
Lisez ceci si vous prévoyez de faire des directives, c'est d'une grande aide: http://docs.angularjs.org/guide/directive
la source
Bien que ma réponse ne soit pas liée aux tables de données, elle aborde le problème de la manipulation DOM et par exemple l'initialisation du plugin jQuery pour les directives utilisées sur les éléments dont le contenu est mis à jour de manière asynchrone.
Au lieu d'implémenter un délai d'attente, vous pouvez simplement ajouter une montre qui écoutera les changements de contenu (ou même des déclencheurs externes supplémentaires).
Dans mon cas, j'ai utilisé cette solution de contournement pour initialiser un plugin jQuery une fois que le ng-repeat a été fait, ce qui a créé mon DOM interne - dans un autre cas, je l'ai utilisé pour manipuler simplement le DOM après que la propriété scope ait été modifiée au niveau du contrôleur. Voici comment j'ai fait ...
HTML:
JS:
Remarque: au lieu de simplement convertir la variable myContent en booléen à l'attribut my-directive-watch, on pourrait imaginer n'importe quelle expression arbitraire.
Remarque: L' isolement de la portée comme dans l'exemple ci-dessus ne peut être fait qu'une fois par élément - essayer de le faire avec plusieurs directives sur le même élément entraînera une erreur $ compile: multidir - voir: https://docs.angularjs.org / erreur / $ compile / multidir
la source
Je suis peut-être en retard pour répondre à cette question. Mais quelqu'un peut encore tirer profit de ma réponse.
J'ai eu un problème similaire et dans mon cas je ne peux pas changer la directive puisque, c'est une bibliothèque et changer un code de la bibliothèque n'est pas une bonne pratique. Donc ce que j'ai fait a été d'utiliser une variable pour attendre le chargement de la page et d'utiliser ng-if dans mon html pour attendre le rendu de l'élément particulier.
Dans mon contrôleur:
Dans mon html (dans mon cas, le composant html est un canevas)
la source
J'ai eu le même problème, mais en utilisant Angular + DataTable avec un
fnDrawCallback
+ groupement de lignes + $ directives imbriquées compilées. J'ai placé le $ timeout dans mafnDrawCallback
fonction pour corriger le rendu de la pagination.Avant l'exemple, basé sur la source de row_grouping:
Après exemple:
Même un court délai d'expiration était suffisant pour permettre à Angular de restituer mes directives Angular compilées.
la source
Aucune des solutions n'a fonctionné pour moi n'accepte d'utiliser un délai d'expiration. C'est parce que j'utilisais un modèle qui était créé dynamiquement pendant le postLink.
Notez cependant qu'il peut y avoir un timeout de '0' car le timeout ajoute la fonction appelée à la file d'attente du navigateur qui se produira après le moteur de rendu angulaire car elle est déjà dans la file d'attente.
Reportez-vous à ceci: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering
la source
Voici une directive pour avoir des actions programmées après un rendu peu profond. Par superficiel, je veux dire qu'il évaluera après cet élément même rendu et qui n'aura aucun rapport avec le moment où son contenu sera rendu. Donc, si vous avez besoin d'un sous-élément pour effectuer une action de post-rendu, vous devriez envisager de l'utiliser ici:
alors vous pouvez faire:
<div after-render></div>
ou avec toute expression utile comme:
<div after-render="$emit='onAfterThisConcreteThingRendered'"></div>
la source
Je l'ai fait fonctionner avec la directive suivante:
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 de chameau.
2) assurez-vous que l'application est définie avant la directive. Par exemple, définition et directive d'application simples.
la source
Suite au fait que l'ordre de chargement ne peut être anticipé, une solution simple peut être utilisée.
Regardons la relation directive-«utilisateur de directive». Habituellement, l'utilisateur de la directive fournira des données à la directive ou utilisera certaines fonctionnalités (fonctions) fournies par la directive. La directive, d'autre part, s'attend à ce que certaines variables soient définies sur son champ d'application.
Si nous pouvons nous assurer que tous les joueurs ont toutes leurs exigences d'action remplies avant de tenter d'exécuter ces actions, tout devrait bien se passer.
Et maintenant la directive:
et maintenant l'utilisateur de la directive html
et quelque part dans le contrôleur du composant qui utilise la directive:
C'est à peu près ça. Il y a beaucoup de frais généraux 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.
la source