Dans jQuery, est-il possible d' appeler un rappel ou de déclencher un événement après qu'un appel de .each()
(ou de tout autre type de rappel itératif) soit terminé .
Par exemple, je voudrais que cette "fondu et suppression" se termine
$(parentSelect).nextAll().fadeOut(200, function() {
$(this).remove();
});
avant de faire quelques calculs et d'insérer de nouveaux éléments après le $(parentSelect)
. Mes calculs sont incorrects si les éléments existants sont toujours visibles par jQuery et que dormir / retarder une durée arbitraire (200 pour chaque élément) semble au mieux être une solution fragile.
Je peux facilement .bind()
la logique nécessaire à un rappel d'événement , mais je ne sais pas comment proprement Invoke l' .trigger()
après ce qui précède itération terminée . De toute évidence, je ne peux pas invoquer le déclencheur à l'intérieur de l'itération car il se déclencherait plusieurs fois.
Dans le cas de $.each()
, j'ai envisagé d'ajouter quelque chose à la fin de l'argument de données (que je rechercherais manuellement dans le corps de l'itération) mais je détesterais être forcé à cela, alors j'espérais qu'il y avait un autre élégant moyen de contrôler le flux par rapport aux rappels itératifs.
Réponses:
Une alternative à la réponse de @ tv:
var elems = $(parentSelect).nextAll(), count = elems.length; elems.each( function(i) { $(this).fadeOut(200, function() { $(this).remove(); if (!--count) doMyThing(); }); });
Notez qu'elle
.each()
est elle - même synchrone - l'instruction qui suit l'appel à.each()
ne sera exécutée qu'une fois l'.each()
appel terminé. Cependant, les opérations asynchrones lancées dans l'.each()
itération se poursuivront bien sûr à leur manière. C'est le problème ici: les appels à atténuer les éléments sont des animations pilotées par le minuteur, et celles-ci continuent à leur propre rythme.La solution ci-dessus, par conséquent, garde une trace du nombre d'éléments estompés. Chaque appel à
.fadeOut()
reçoit un rappel d'achèvement. Lorsque le rappel remarque qu'il est compté à travers tous les éléments d'origine impliqués, une action ultérieure peut être entreprise avec la certitude que tout l'évanouissement est terminé.C'est une réponse vieille de quatre ans (à ce stade en 2014). Une manière moderne de faire cela impliquerait probablement d'utiliser le mécanisme Différé / Promise, bien que ce qui précède soit simple et devrait fonctionner correctement.
la source
Il est probablement trop tard mais je pense que ce code fonctionne ...
$blocks.each(function(i, elm) { $(elm).fadeOut(200, function() { $(elm).remove(); }); }).promise().done( function(){ alert("All was done"); } );
la source
Ok, c'est peut-être un peu après coup, mais .promise () devrait également réaliser ce que vous recherchez.
Documentation de la promesse
Un exemple d'un projet sur lequel je travaille:
$( '.panel' ) .fadeOut( 'slow') .promise() .done( function() { $( '#' + target_panel ).fadeIn( 'slow', function() {}); });
:)
la source
JavaScript s'exécute de manière synchrone, donc tout ce que vous placez après
each()
ne fonctionnera pas tant qu'il ne sera paseach()
terminé.Considérez le test suivant:
var count = 0; var array = []; // populate an array with 1,000,000 entries for(var i = 0; i < 1000000; i++) { array.push(i); } // use each to iterate over the array, incrementing count each time $.each(array, function() { count++ }); // the alert won't get called until the 'each' is done // as evidenced by the value of count alert(count);
Lorsque l'alerte est appelée, le nombre sera égal à 1000000 car l'alerte ne s'exécutera pas tant qu'elle ne sera pas
each()
terminée.la source
each
et planifiez chaque animation séparément, vous devez toujours déclencher l'événement une fois l'animation terminée, et non chacune.each()
problème. C'est pourquoi j'ai jeté cette réponse dans le mélange.each
n'étaient pas garanties d'être appelées auparavantalert
. pourriez-vous m'expliquer ou me montrer la lecture à ce sujet?J'ai trouvé beaucoup de réponses traitant des tableaux mais pas d'un objet json. Ma solution consistait simplement à parcourir l'objet une fois tout en incrémentant un compteur, puis lors de l'itération à travers l'objet pour exécuter votre code, vous pouvez incrémenter un deuxième compteur. Ensuite, vous comparez simplement les deux compteurs ensemble et obtenez votre solution. Je sais que c'est un peu maladroit mais je n'ai pas encore trouvé de solution plus élégante. Voici mon exemple de code:
var flag1 = flag2 = 0; $.each( object, function ( i, v ) { flag1++; }); $.each( object, function ( ky, val ) { /* Your code here */ flag2++; }); if(flag1 === flag2) { your function to call at the end of the iteration }
Comme je l'ai dit, ce n'est pas le plus élégant, mais cela fonctionne et cela fonctionne bien et je n'ai pas encore trouvé de meilleure solution.
Salutations, JP
la source
J'utilise quelque chose comme ça:
$.when( $.each(yourArray, function (key, value) { // Do Something in loop here }) ).then(function () { // After loop ends. });
la source
Si vous êtes prêt à faire quelques étapes, cela pourrait fonctionner. Cela dépend cependant de la fin des animations dans l'ordre. Je ne pense pas que cela devrait être un problème.
var elems = $(parentSelect).nextAll(); var lastID = elems.length - 1; elems.each( function(i) { $(this).fadeOut(200, function() { $(this).remove(); if (i == lastID) { doMyThing(); } }); });
la source
qu'en est-il de
$(parentSelect).nextAll().fadeOut(200, function() { $(this).remove(); }).one(function(){ myfunction(); });
la source
Vous devez mettre le reste de votre demande en file d'attente pour que cela fonctionne.
var elems = $(parentSelect).nextAll(); var lastID = elems.length - 1; elems.each( function(i) { $(this).fadeOut(200, function() { $(this).remove(); if (i == lastID) { $j(this).queue("fx",function(){ doMyThing;}); } }); });
la source
Je rencontre le même problème et je l'ai résolu avec une solution comme le code suivant:
var drfs = new Array(); var external = $.Deferred(); drfs.push(external.promise()); $('itemSelector').each( function() { //initialize the context for each cycle var t = this; // optional var internal = $.Deferred(); // after the previous deferred operation has been resolved drfs.pop().then( function() { // do stuff of the cycle, optionally using t as this var result; //boolean set by the stuff if ( result ) { internal.resolve(); } else { internal.reject(); } } drfs.push(internal.promise()); }); external.resolve("done"); $.when(drfs).then( function() { // after all each are resolved });
La solution résout le problème suivant: pour synchroniser les opérations asynchrones lancées dans l'itération .each (), à l'aide de l'objet Deferred.
la source
Peut-être une réponse tardive, mais il existe un package pour gérer cela https://github.com/ACFBentveld/Await
var myObject = { // or your array 1 : 'My first item', 2 : 'My second item', 3 : 'My third item' } Await.each(myObject, function(key, value){ //your logic here }); Await.done(function(){ console.log('The loop is completely done'); });
la source