Je veux appeler une fonction jQuery ciblant div avec table. Cette table est remplie avec ng-repeat
.
Quand je l'appelle
$(document).ready()
Je n'ai aucun résultat.
Aussi
$scope.$on('$viewContentLoaded', myFunc);
n'aide pas.
Est-il possible d'exécuter la fonction juste après la fin de la population ng-repeat? J'ai lu un conseil sur l'utilisation de custom directive
, mais je ne sais pas comment l'utiliser avec ng-repeat et ma div ...
En effet, vous devriez utiliser des directives, et il n'y a pas d'événement lié à la fin d'une boucle ng-Repeat (chaque élément est construit individuellement et a son propre événement). Mais a) utiliser des directives pourrait suffire et b) il existe quelques propriétés spécifiques à ng-Repeat que vous pouvez utiliser pour créer votre événement "on ngRepeat completed".
Plus précisément, si vous souhaitez simplement styler/ajouter des événements à l’ensemble de la table, vous pouvez le faire en utilisant une directive qui englobe tous les éléments ngRepeat. D'autre part, si vous souhaitez traiter chaque élément de manière spécifique, vous pouvez utiliser une directive dans ngRepeat, qui agira sur chaque élément après sa création.
Ensuite, il y a les propriétés $index
, $first
, $middle
et $last
que vous pouvez utiliser pour déclencher des événements. Donc pour ce HTML:
<div ng-controller="Ctrl" my-main-directive>
<div ng-repeat="thing in things" my-repeat-directive>
thing {{thing}}
</div>
</div>
Vous pouvez utiliser des directives comme ceci:
angular.module('myApp', [])
.directive('myRepeatDirective', function() {
return function(scope, element, attrs) {
angular.element(element).css('color','blue');
if (scope.$last){
window.alert("im the last!");
}
};
})
.directive('myMainDirective', function() {
return function(scope, element, attrs) {
angular.element(element).css('border','5px solid red');
};
});
Voyez-le en action dans ce Plunker . J'espère que ça aide!
Si vous voulez simplement exécuter du code à la fin de la boucle, voici une variante un peu plus simple qui ne nécessite pas de gestion d'événements supplémentaire:
<div ng-controller="Ctrl">
<div class="thing" ng-repeat="thing in things" my-post-repeat-directive>
thing {{thing}}
</div>
</div>
function Ctrl($scope) {
$scope.things = [
'A', 'B', 'C'
];
}
angular.module('myApp', [])
.directive('myPostRepeatDirective', function() {
return function(scope, element, attrs) {
if (scope.$last){
// iteration is complete, do whatever post-processing
// is necessary
element.parent().css('border', '1px solid black');
}
};
});
Il n'est pas nécessaire de créer une directive, en particulier pour avoir un événement ng-repeat
complete.
ng-init
fait la magie pour vous.
<div ng-repeat="thing in things" ng-init="$last && finished()">
le $last
s'assure que finished
ne se déclenche que lorsque le dernier élément a été rendu dans le DOM.
N'oubliez pas de créer l'événement $scope.finished
.
Bonne codage !!
EDIT: 23 Oct 2016
Si vous souhaitez également appeler la fonction finished
lorsqu'il n'y a aucun élément dans le tableau, vous pouvez utiliser la solution suivante
<div style="display:none" ng-init="things.length < 1 && finished()"></div>
//or
<div ng-if="things.length > 0" ng-init="finished()"></div>
Ajoutez simplement la ligne ci-dessus en haut de l’élément ng-repeat
. Il vérifiera si le tableau n'a aucune valeur et appellera la fonction en conséquence.
Par exemple.
<div ng-if="things.length > 0" ng-init="finished()"></div>
<div ng-repeat="thing in things" ng-init="$last && finished()">
Voici une directive repeat-done qui appelle une fonction spécifiée lorsque la valeur est true. J'ai trouvé que la fonction appelée doit utiliser $ timeout avec intervalle = 0 avant de manipuler DOM, telle que l'initialisation des info-bulles sur les éléments rendus. jsFiddle: http://jsfiddle.net/tQw6w/
Dans $ scope.layoutDone, essayez de commenter la ligne $ timeout et de ne pas commenter "NOT CORRECT!" ligne pour voir la différence dans les info-bulles.
<ul>
<li ng-repeat="feed in feedList" repeat-done="layoutDone()" ng-cloak>
<a href="{{feed}}" title="view at {{feed | hostName}}" data-toggle="tooltip">{{feed | strip_http}}</a>
</li>
</ul>
JS:
angular.module('Repeat_Demo', [])
.directive('repeatDone', function() {
return function(scope, element, attrs) {
if (scope.$last) { // all are rendered
scope.$eval(attrs.repeatDone);
}
}
})
.filter('strip_http', function() {
return function(str) {
var http = "http://";
return (str.indexOf(http) == 0) ? str.substr(http.length) : str;
}
})
.filter('hostName', function() {
return function(str) {
var urlParser = document.createElement('a');
urlParser.href = str;
return urlParser.hostname;
}
})
.controller('AppCtrl', function($scope, $timeout) {
$scope.feedList = [
'http://feeds.feedburner.com/TEDTalks_video',
'http://feeds.nationalgeographic.com/ng/photography/photo-of-the-day/',
'http://sfbay.craigslist.org/eng/index.rss',
'http://www.slate.com/blogs/trending.fulltext.all.10.rss',
'http://feeds.current.com/homepage/en_US.rss',
'http://feeds.current.com/items/popular.rss',
'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml'
];
$scope.layoutDone = function() {
//$('a[data-toggle="tooltip"]').tooltip(); // NOT CORRECT!
$timeout(function() { $('a[data-toggle="tooltip"]').tooltip(); }, 0); // wait...
}
})
Voici une approche simple utilisant ng-init
qui ne nécessite même pas de directive personnalisée. Cela a bien fonctionné pour moi dans certains scénarios, par exemple. ayant besoin de faire défiler automatiquement un élément de plusieurs éléments répétés jusqu'à un élément particulier lors du chargement de la page, la fonction de défilement doit donc attendre que le ng-repeat
ait terminé le rendu dans le DOM avant de pouvoir se déclencher.
<div ng-controller="MyCtrl">
<div ng-repeat="thing in things">
thing: {{ thing }}
</div>
<div ng-init="fireEvent()"></div>
</div>
myModule.controller('MyCtrl', function($scope, $timeout){
$scope.things = ['A', 'B', 'C'];
$scope.fireEvent = function(){
// This will only run after the ng-repeat has rendered its things to the DOM
$timeout(function(){
$scope.$broadcast('thingsRendered');
}, 0);
};
});
Notez que cela n’est utile que pour les fonctions que vous devez appeler une fois après le rendu initial de ng-repeat. Si vous avez besoin d'appeler une fonction chaque fois que le contenu de ng-repeat est mis à jour, vous devrez utiliser l'une des autres réponses de ce fil avec une directive personnalisée.
En complément de la réponse de Pavel , il serait plus facile de comprendre et de comprendre:
<ul>
<li ng-repeat="item in items"
ng-init="$last ? doSomething() : angular.noop()">{{item}}</li>
</ul>
Pourquoi pensez-vous que angular.noop
existe-t-il en premier lieu ...?
Avantages:
Vous n'êtes pas obligé d'écrire une directive pour cela ...
Peut-être une approche un peu plus simple avec ngInit
et la méthode debounce
de Lodash sans la nécessité d'une directive personnalisée:
Manette:
$scope.items = [1, 2, 3, 4];
$scope.refresh = _.debounce(function() {
// Debounce has timeout and prevents multiple calls, so this will be called
// once the iteration finishes
console.log('we are done');
}, 0);
Modèle:
<ul>
<li ng-repeat="item in items" ng-init="refresh()">{{item}}</li>
</ul>
Il existe même une solution AngularJS pure plus simple utilisant un opérateur ternaire:
Modèle:
<ul>
<li ng-repeat="item in items" ng-init="$last ? doSomething() : null">{{item}}</li>
</ul>
Sachez que ngInit utilise la phase de compilation préalable à la liaison - c’est-à-dire que l’expression est appelée avant le traitement des directives enfant. Cela signifie qu'un traitement asynchrone pourrait être requis.
Lorsque vous vérifiez la variable scope.$last
, vous devrez peut-être également envelopper votre déclencheur avec un setTimeout(someFn, 0)
. Un setTimeout 0
est une technique acceptée en javascript et il était impératif que mon directive
fonctionne correctement.
<div ng-repeat="i in items">
<label>{{i.Name}}</label>
<div ng-if="$last" ng-init="ngRepeatFinished()"></div>
</div>
Ma solution a été d'ajouter un div pour appeler une fonction si l'élément était le dernier d'une répétition.
Il s’agit d’une amélioration des idées exprimées dans d’autres réponses afin de montrer comment accéder aux propriétés ngRepeat ($ index, $ premier, $ moyen, $ dernier, $ pair, $ impair) lorsque vous utilisez la syntaxe déclarative et isolate scope ( Google a recommandé la meilleure pratique) avec une directive élément. Notez la différence principale: scope.$parent.$last
.
angular.module('myApp', [])
.directive('myRepeatDirective', function() {
return {
restrict: 'E',
scope: {
someAttr: '='
},
link: function(scope, element, attrs) {
angular.element(element).css('color','blue');
if (scope.$parent.$last){
window.alert("im the last!");
}
}
};
});
je voudrais ajouter une autre réponse, car la réponse précédente indique que le code nécessaire pour s'exécuter après l'exécution de ngRepeat est un code angular qui, dans ce cas, donne une solution simple et efficace, Certains sont plus génériques que d'autres, et si c'est important le stade du cycle de vie, vous pouvez jeter un oeil à blog de Ben Nadel , à l'exception de l'utilisation de $ parse au lieu de $ eval.
mais selon mon expérience, comme l'OP l'indique, il exécute généralement des plugins ou des méthodes JQuery sur le DOM compilé, ce qui m'a amené à penser que la solution la plus simple consiste à créer une directive avec setTimeout, car la fonction setTimeout est poussée jusqu’à la fin de la file d’attente du navigateur, c’est toujours juste après que tout soit terminé en mode angulaire, généralement ngReapet, qui se poursuit après la fonction postLinking de ses parents
angular.module('myApp', [])
.directive('pluginNameOrWhatever', function() {
return function(scope, element, attrs) {
setTimeout(function doWork(){
//jquery code and plugins
}, 0);
};
});
pour ceux qui se demandent dans ce cas pourquoi ne pas utiliser $ timeout, cela provoque un autre cycle de digestion complètement inutile
Je l'ai fait de cette façon.
Créer la directive
function finRepeat() {
return function(scope, element, attrs) {
if (scope.$last){
// Here is where already executes the jquery
$(document).ready(function(){
$('.materialboxed').materialbox();
$('.tooltipped').tooltip({delay: 50});
});
}
}
}
angular
.module("app")
.directive("finRepeat", finRepeat);
Après que vous l'ajoutiez sur l'étiquette où ce ng-repeat
<ul>
<li ng-repeat="(key, value) in data" fin-repeat> {{ value }} </li>
</ul>
Et prêt à être exécuté à la fin de la répétition.
Je devais rendre des formules en utilisant MathJax après la fin de ng-repeat, aucune des réponses ci-dessus ne résolut mon problème, alors je fis comme ci-dessous. C'est pas une solution intéressante, mais a fonctionné pour moi ...
<div ng-repeat="formula in controller.formulas">
<div>{{formula.string}}</div>
{{$last ? controller.render_formulas() : ""}}
</div>
J'ai trouvé une réponse ici bien pratiqué, mais il fallait encore ajouter un délai
Créez la directive suivante:
angular.module('MyApp').directive('emitLastRepeaterElement', function() {
return function(scope) {
if (scope.$last){
scope.$emit('LastRepeaterElement');
}
}; });
Ajoutez-le à votre répéteur en tant qu'attribut, comme ceci:
<div ng-repeat="item in items" emit-last-repeater-element></div>
Selon Radu:
$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {mycode});
Pour moi cela fonctionne, mais je dois encore ajouter un setTimeout
$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {
setTimeout(function() {
mycode
}, 100); });