Passer des paramètres dans L'événement javascript onClick

J'essaie de passer un paramètre dans l'événement onclick. Voici un exemple de code:

<div id="div"></div>

<script language="javascript" type="text/javascript">
   var div = document.getElementById('div');

   for (var i = 0; i < 10; i++) {
       var link = document.createElement('a');
       link.setAttribute('href', '#');
       link.innerHTML = i + '';
       link.onclick=  function() { onClickLink(i+'');};
       div.appendChild(link);
       div.appendChild(document.createElement('BR'));
       }

   function onClickLink(text) {
       alert('Link ' + text + ' clicked');
       return false;
       }
    </script>

Cependant, chaque fois que je clique sur l'un des liens, l'alerte affiche toujours 'Lien 10 cliqué'!

Quelqu'un peut-il me dire ce que je fais mal?

Merci

47
demandé sur Jamie Wong 2010-08-16 21:34:40

8 réponses

Cela se produit parce que je propage la portée une fois que la fonction est invoquée. Vous pouvez éviter ce problème en utilisant une fermeture.

for (var i = 0; i < 10; i++) {
   var link = document.createElement('a');
   link.setAttribute('href', '#');
   link.innerHTML = i + '';
   link.onclick = (function() {
      var currentI = i;
      return function() { 
          onClickLink(currentI + '');
      }
   })();
   div.appendChild(link);
   div.appendChild(document.createElement('BR'));
}

Ou si vous voulez une syntaxe plus concise, je vous suggère d'utiliser la solution de Nick Craver.

52
répondu Jamie Wong 2012-08-26 15:22:02

Cela se produit parce qu'ils font tous référence au même i variable, qui change chaque boucle, et laissée comme 10 à la fin de la boucle. Vous pouvez le résoudre en utilisant une fermeture comme ceci:

link.onclick = function(j) { return function() { onClickLink(j+''); }; }(i);

Vous pouvez l'essayer ici

Ou this être le lien vous avez cliqué dans ce gestionnaire, comme ceci:

link.onclick = function(j) { return function() { onClickLink.call(this, j); }; }(i);

Vous pouvez essayer cette version ici

36
répondu Nick Craver 2010-08-16 17:41:11
link.onclick = function() { onClickLink(i+''); };

Est une fermeture et stocke une référence à la variable i, pas la valeur que i contient lorsque la fonction est créée. Une solution serait d'envelopper le contenu de la for boucle en fonction de cela:

for (var i = 0; i < 10; i++) (function(i) {
    var link = document.createElement('a');
    link.setAttribute('href', '#');
    link.innerHTML = i + '';
    link.onclick=  function() { onClickLink(i+'');};
    div.appendChild(link);
    div.appendChild(document.createElement('BR'));
}(i));
3
répondu Ryan Tenney 2010-08-16 17:40:48

Essayez ceci:

<div id="div"></div>

<script language="javascript" type="text/javascript">
   var div = document.getElementById('div');

   for (var i = 0; i < 10; i++) {
       var f = function() {
           var link = document.createElement('a');
           var j = i; // this j is scoped to our anonymous function
                      // while i is scoped outside the anonymous function,
                      //  getting incremented by the for loop
           link.setAttribute('href', '#');
           link.innerHTML = j + '';
           link.onclick=  function() { onClickLink(j+'');};
           div.appendChild(link);
           div.appendChild(document.createElement('br')); // lower case BR, please!
       }(); // call the function immediately
   }

   function onClickLink(text) {
       alert('Link ' + text + ' clicked');
       return false;
   }
</script>
1
répondu Richard JP Le Guen 2010-08-16 17:40:33

Ou vous pouvez utiliser cette ligne:

 link.setAttribute('onClick', 'onClickLink('+i+')');

Au lieu de celui-ci:

link.onclick=  function() { onClickLink(i+'');};
1
répondu aniri 2010-08-16 17:44:18

Un autre moyen simple (pourrait ne pas être la meilleure pratique) mais fonctionne comme charm. Construisez la balise HTML de votre élément(lien hypertexte ou bouton) dynamiquement avec javascript, et peut également passer plusieurs paramètres.

// variable to hold the HTML Tags 
var ProductButtonsHTML  ="";

//Run your loop
for (var i = 0; i < ProductsJson.length; i++){
// Build the <input> Tag with the required parameters for Onclick call. Use double quotes.

ProductButtonsHTML += " <input type='button' value='" + ProductsJson[i].DisplayName + "'  
onclick = \"BuildCartById('" + ProductsJson[i].SKU+ "'," + ProductsJson[i].Id + ")\"></input> ";

}

// Add the Tags to the Div's innerHTML.
document.getElementById("divProductsMenuStrip").innerHTML = ProductButtonsHTML;
1
répondu Kiran Kumar Veerabatheni 2012-07-17 00:12:45

Il est probablement préférable de créer une fonction dédiée pour créer le lien afin d'éviter de créer deux fonctions anonymes. Ainsi:

<div id="div"></div>

<script>
  function getLink(id)
  {
    var link = document.createElement('a');
    link.setAttribute('href', '#');
    link.innerHTML = id;
    link.onclick = function()
    {
      onClickLink(id);
    };
    link.style.display = 'block';
    return link;
  }
  var div = document.getElementById('div');
  for (var i = 0; i < 10; i += 1)
  {
    div.appendChild(getLink(i.toString()));
  }
</script>

Bien que dans les deux cas, vous vous retrouvez avec deux fonctions, je pense juste qu'il est préférable de l'envelopper dans une fonction sémantiquement plus facile à comprendre.

1
répondu Yeti 2012-12-23 15:30:44

Onclick vs addEventListener. Une question de préférence peut-être (où IE > 9).

// Using closures
function onClickLink(e, index) {   
    alert(index);
    return false;
}

var div = document.getElementById('div');

for (var i = 0; i < 10; i++) {
    var link = document.createElement('a');

    link.setAttribute('href', '#');
    link.innerHTML = i + '';
    link.addEventListener('click', (function(e) {
        var index = i;
        return function(e) {
            return onClickLink(e, index);
        }
    })(), false);
    div.appendChild(link);
    div.appendChild(document.createElement('BR'));
}

Comment buter juste en utilisant un attribut data-* simple, pas aussi cool qu'une fermeture, mais..

function onClickLink(e) {       
    alert(e.target.getAttribute('data-index'));
    return false;
}

var div = document.getElementById('div');

for (var i = 0; i < 10; i++) {
    var link = document.createElement('a');

    link.setAttribute('href', '#');
    link.setAttribute('data-index', i);
    link.innerHTML = i + ' Hello';        
    link.addEventListener('click', onClickLink, false);
    div.appendChild(link);
    div.appendChild(document.createElement('BR'));
}
1
répondu Alex Nolasco 2016-01-17 04:00:42