Ce que j'essaye d'implémenter est fondamentalement un gestionnaire "on ng repeat done rendering". Je suis capable de détecter quand c'est fait mais je n'arrive pas à comprendre comment en déclencher une fonction.
Vérifiez le violon: http://jsfiddle.net/paulocoelho/BsMqq/3/
JS
var module = angular.module('testApp', [])
.directive('onFinishRender', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
element.ready(function () {
console.log("calling:"+attr.onFinishRender);
// CALL TEST HERE!
});
}
}
}
});
function myC($scope) {
$scope.ta = [1, 2, 3, 4, 5, 6];
function test() {
console.log("test executed");
}
}
HTML
<div ng-app="testApp" ng-controller="myC">
<p ng-repeat="t in ta" on-finish-render="test()">{{t}}</p>
</div>
Réponse : Travailler le violon à partir de finishmove: http://jsfiddle.net/paulocoelho/BsMqq/4/
element.ready()
extrait? Je veux dire .. est-ce une sorte de plugin jQuery que vous avez, ou devrait-il être déclenché lorsque l'élément est prêt?Réponses:
Notez que je ne l'ai pas utilisé
.ready()
mais plutôt enveloppé dans un$timeout
.$timeout
s'assure qu'il est exécuté lorsque les éléments ng-répétés ont VRAIMENT fini le rendu (car le$timeout
s'exécutera à la fin du cycle de résumé en cours - et il appellera également en$apply
interne, contrairement àsetTimeout
). Ainsi, une fois lang-repeat
fin de, nous utilisons$emit
pour émettre un événement vers les étendues externes (étendues frère et parent).Et puis dans votre contrôleur, vous pouvez l'attraper avec
$on
:Avec html qui ressemble à ceci:
la source
$timeout
(ce qui est essentiellementsetTimeout
+ Angular$scope.$apply()
) avecsetInterval
.$timeout
ne s'exécutera qu'une seule fois parif
condition, et ce sera au début du$digest
cycle suivant . Pour plus d'informations sur les délais d' expirationsetTimeout()
avec 0 retard est une autre question, mais je dois dire que je n'ai jamais rencontré de spécification réelle pour la file d'attente des événements du navigateur, ce qui est impliqué par le thread unique et l'existence desetTimeout()
.on-finish-render="ngRepeatFinished"
? Lorsque j'attribueon-finish-render="helloworld"
, cela fonctionne de la même manière.Utilisez $ evalAsync si vous souhaitez que votre rappel (c'est-à-dire test ()) soit exécuté après la construction du DOM, mais avant le rendu du navigateur. Cela évitera le scintillement - réf .
Violon .
Si vous voulez vraiment appeler votre rappel après le rendu, utilisez $ timeout:
Je préfère $ eval au lieu d'un événement. Avec un événement, nous devons connaître le nom de l'événement et ajouter du code à notre contrôleur pour cet événement. Avec $ eval, il y a moins de couplage entre le contrôleur et la directive.
la source
$last
? Je ne le trouve pas dans les documents. A-t-il été supprimé?$last
est défini sur la portée si unng-repeat
est actif sur l'élément.$timeout
.Les réponses qui ont été données jusqu'à présent ne fonctionneront que la première fois que le sera
ng-repeat
rendu , mais si vous avez une dynamiqueng-repeat
, ce qui signifie que vous allez ajouter / supprimer / filtrer des éléments, et vous devez être averti chaque fois que leng-repeat
est rendu, ces solutions ne fonctionneront pas pour vous.Donc, si vous devez être averti à CHAQUE FOIS que le
ng-repeat
rendu est rendu et pas seulement la première fois, j'ai trouvé un moyen de le faire, c'est assez `` hacky '', mais cela fonctionnera bien si vous savez ce que vous êtes Faire. Utilisez-le$filter
dans votreng-repeat
avant d'utiliser tout autre$filter
:Il s'agira d'
$emit
un événement appelé àngRepeatFinished
chaque fois que le serang-repeat
rendu.Comment l'utiliser:
Le
ngRepeatFinish
filtre doit être appliqué directement à unArray
ou à unObject
défini dans votre$scope
, vous pouvez ensuite appliquer d'autres filtres.Comment NE PAS l'utiliser:
N'appliquez pas d'autres filtres en premier, puis appliquez le
ngRepeatFinish
filtre.Quand dois-je l'utiliser?
Si vous souhaitez appliquer certains styles CSS dans le DOM une fois le rendu de la liste terminé, car vous devez prendre en compte les nouvelles dimensions des éléments DOM qui ont été restitués par le
ng-repeat
. (BTW: ce type d'opérations doit être effectué dans une directive)Ce qu'il NE FAUT PAS FAIRE dans la fonction qui gère l'
ngRepeatFinished
événement:N'effectuez pas de fonction
$scope.$apply
dans cette fonction ou vous mettrez Angular dans une boucle sans fin qu'Angular ne pourra pas détecter.Ne l'utilisez pas pour apporter des modifications aux
$scope
propriétés, car ces modifications ne seront pas reflétées dans votre vue jusqu'à la prochaine$digest
boucle, et puisque vous ne pouvez pas effectuer une,$scope.$apply
elles ne seront d'aucune utilité."Mais les filtres ne sont pas destinés à être utilisés comme ça !!"
Non, ils ne le sont pas, c'est un hack, si vous ne l'aimez pas, ne l'utilisez pas. Si vous connaissez une meilleure façon d'accomplir la même chose, faites-le moi savoir.
Résumer
la source
$last
élément est également modifié, une simplengRepeatFinish
directive en vérifiant$last
maintenant fonctionnera. Dès que ngRepeatFinish est appelé, je supprime l'élément factice. (Je le cache également avec CSS pour qu'il n'apparaisse pas brièvement)Mark Rajcok
fonctionne parfaitement à chaque rendu de la répétition ng (par exemple en raison d'un changement de modèle). Cette solution hacky n'est donc pas nécessaire.Si vous devez appeler différentes fonctions pour différentes répétitions ng sur le même contrôleur, vous pouvez essayer quelque chose comme ceci:
La directive:
Dans votre contrôleur, capturez les événements avec $ on:
Dans votre modèle avec plusieurs ng-repeat
la source
Les autres solutions fonctionneront correctement lors du chargement initial de la page, mais l'appel de $ timeout à partir du contrôleur est le seul moyen de garantir que votre fonction est appelée lorsque le modèle change. Voici un violon qui utilise $ timeout. Pour votre exemple, ce serait:
ngRepeat n'évaluera une directive que lorsque le contenu de la ligne est nouveau, donc si vous supprimez des éléments de votre liste, onFinishRender ne se déclenchera pas. Par exemple, essayez d'entrer des valeurs de filtre dans ces émetteurs violons .
la source
ta
en$scope.$watch("ta",...
?Si vous n'êtes pas opposé à l'utilisation d'accessoires de portée à deux dollars et que vous écrivez une directive dont le seul contenu est une répétition, il existe une solution assez simple (en supposant que vous ne vous souciez que du rendu initial). Dans la fonction de liaison:
Ceci est utile dans les cas où vous avez une directive qui doit effectuer une manipulation DOM en fonction de la largeur ou de la hauteur des membres d'une liste rendue (ce qui, je pense, est la raison la plus probable pour laquelle vous poseriez cette question), mais ce n'est pas aussi générique comme les autres solutions qui ont été proposées.
la source
Une solution à ce problème avec un ngRepeat filtré aurait pu être avec les événements de mutation , mais ils sont obsolètes (sans remplacement immédiat).
Puis j'ai pensé à une autre facile:
Cela se connecte aux méthodes Node.prototype de l'élément parent avec un délai d'attente $ à une seule tick pour surveiller les modifications successives.
Cela fonctionne généralement correctement, mais j'ai eu quelques cas où l'altDone serait appelé deux fois.
Encore une fois ... ajoutez cette directive au parent de ngRepeat.
la source
appendChild
aussi l' ajout (puisque je n'ai utiliséinsertBefore
queremoveChild
) et dans le code ci-dessus.Très facile, c'est comme ça que je l'ai fait.
la source
Veuillez jeter un œil au violon, http://jsfiddle.net/yNXS2/ . Étant donné que la directive que vous avez créée n'a pas créé de nouvelle portée, j'ai continué dans la voie.
$scope.test = function(){...
rendu cela possible.la source
Je suis très surpris de ne pas voir la solution la plus simple parmi les réponses à cette question. Ce que vous voulez faire, c'est ajouter une
ngInit
directive sur votre élément répété (l'élément avec langRepeat
directive) en vérifiant$last
(une variable spéciale définie dans la portée parngRepeat
laquelle indique que l'élément répété est le dernier de la liste). Si$last
est vrai, nous rendons le dernier élément et nous pouvons appeler la fonction que nous voulons.Le code complet de votre balisage HTML serait:
Vous n'avez pas besoin de code JS supplémentaire dans votre application en plus de la fonction scope que vous souhaitez appeler (dans ce cas,
test
) car ellengInit
est fournie par Angular.js. Assurez-vous simplement d'avoir votretest
fonction dans la portée afin qu'elle soit accessible à partir du modèle:la source