2008-12-04 9 views
34

Je travaille avec un peu de code html et Javascript que j'ai repris de quelqu'un d'autre. La page recharge une table de données (via une requête asynchrone) toutes les dix secondes, puis reconstruit la table en utilisant du code DOM. Le code en question ressemble à ceci:Les gestionnaires d'événements dans une boucle Javascript - besoin d'une fermeture?

var blah = xmlres.getElementsByTagName('blah'); 
for(var i = 0; i < blah.length; i++) { 
    var td = document.createElement('td'); 
    var select = document.createElement('select'); 
    select.setAttribute("...", "..."); 
    select.onchange = function() { 
     onStatusChanged(select, callid, anotherid); 
    }; 
    td.appendChild(select); 
} 

Lorsque l'événement onchange est tiré d'un élément <select> cependant, il semble que les mêmes valeurs sont transmises à la méthode onStatusChanged() pour chaque <select> dans le tableau (I » J'ai vérifié qu'à chaque itération de la boucle, callid et anotherid reçoivent de nouvelles valeurs distinctes).

Je suppose que cela se produit en raison de la nature de la définition du gestionnaire d'événements, avec la syntaxe select.onchange = function(). Si je comprends comment cela fonctionne correctement, cette syntaxe définit une fermeture pour l'événement onchange comme une fonction qui se réfère à ces deux références, qui finissent par avoir une valeur finale de ce qui leur est attribué lors de la dernière itération de la boucle. Lorsque l'événement se déclenche, la valeur référencée par callid et anotherid est la valeur définie dans la dernière itération, et non la valeur définie à l'itération individuelle.

Existe-t-il un moyen de copier la valeur des paramètres que je passe à onStatusChanged()?

J'ai changé le titre pour mieux refléter la question et la réponse acceptée.

Répondre

49

Vous devez, en effet, implémenter une fermeture ici. Cette devrait travail (laissez-moi savoir - je ne pas testé)

var blah = xmlres.getElementsByTagName('blah'); 
for(var i = 0; i < blah.length; i++) { 
    var td = document.createElement('td'); 
    var select = document.createElement('select'); 
    select.setAttribute("...", "..."); 
    select.onchange = function(s,c,a) 
    { 
     return function() 
     { 
      onStatusChanged(s,c,a); 
     } 
    }(select, callid, anotherid); 
    td.appendChild(select); 
} 
+1

cela ne fait le travail - merci! –

+0

Aussi une autre solution que j'ai découverte - une solution de contournement, vraiment - serait de stocker le callid et otherid comme attributs dans l'élément DOM, et à l'intérieur du eventhandler référence juste ceux via this.getAttribute() –

+0

Je ne l'appellerais pas une solution de contournement. Ce que je m'attendrais à ce que le gestionnaire soit réglé une fois (pas à chaque fois dans la boucle) et que je lui fasse découvrir les variables lui-même. – dkretz

Questions connexes