2010-08-16 30 views
45

Estoy tratando de pasar un parámetro en el evento onclick. A continuación se muestra un ejemplo de código:Pasar parámetros en Javascript onClick evento

<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> 

Sin embargo cada vez que haga clic en cualquier enlace de la alerta siempre muestra 'Enlace 10 hace clic en'!

¿Alguien puede decirme qué estoy haciendo mal?

Gracias

Respuesta

50

Esto sucede porque la i se propaga hasta el alcance una vez que la función se invoca. Puede evitar este problema usando un cierre.

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')); 
} 

O si desea una sintaxis más concisa, le sugiero que utilice la solución de Nick Craver.

+0

Gracias, está funcionando ahora! – fatcatz

+0

¡Descripción impresionante de este Jamie! –

+0

¡Ja! Porque ese * closure * que definimos en el RHS de 'link.onclick =' tiene acceso a la función que lo contiene, lo que significa que 'i' adentro hay una referencia al' i' externo, y no un valor copiado (como con normal * pasar por valor * pasar de argumentos)! :)) Encantador. Finalmente entiendo esto: D – Bloke

1

Prueba esto:

<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> 
3
link.onclick = function() { onClickLink(i+''); }; 

un cierre y almacena una referencia a la variable i, no el valor que i se mantiene cuando se crea la función. Una solución sería para envolver el contenido del bucle for en una función de hacer esto:

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)); 
+0

Creo que tienes algunos paréntesis desequilibrados allí. ¿Debería ser '}) (i);' en la última línea? –

+1

Eso funciona, al igual que omitir los paréntesis externos, pero este es el estilo "aprobado por Crockford": http://stackoverflow.com/questions/939386/javascript-immediate-function-invocation-syntax –

+0

Ah, es bueno saberlo. –

34

Esto está ocurriendo porque todos referencia a la misma variable dei, que está cambiando cada bucle, y se fue tan 10 al final del ciclo. Se puede resolver mediante un cierre de la siguiente manera:

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

You can give it a try here

O bien, hacer this ser el vínculo que ha hecho clic en ese controlador, así:

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

You can try that version here

+1

Para que quede claro: ¿está devolviendo la declaración de una función anónima que acepta un parámetro _j_ y en el mismo momento también está pasando el parámetro real? (el _ (i) _) – dierre

+3

@dierre - El '(i)' invoca la 'función (j)' con el parámetro que es el 'i' actual, lo que hace que devuelva la función en la que está el valor copiado en el el cierre, ya no está conectado a 'i', ¿tiene sentido? –

+0

Parece lo mismo que estoy diciendo, pero no estoy seguro: para mí _función (j) {return function() {onClickLink (j + ''); }; } _ es _MyAnonymFunction (j) _. Lo que estoy viendo es _link.onclick = MyAnonymFunction (i); _ – dierre

1

o puede usar esta línea:

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

en lugar de éste:

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

setAttribute para onclicks y estilos no funcionan en srijan

1

Otra forma sencilla (podría no ser la mejor práctica), pero funciona como encanto. Cree la etiqueta HTML de su elemento (hyperLink o Button) dinámicamente con javascript y también puede pasar varios parámetros.

// 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

Probablemente sea mejor crear una función dedicada para crear el enlace para evitar la creación de dos funciones anónimas. Por lo tanto:

<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> 

Aunque en ambos casos se termina con dos funciones, sólo creo que es mejor que lo envuelve en una función que es semánticamente más fácil de comprender.

1

onclick vs addEventListener. Una cuestión de preferencia quizás (donde 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')); 
} 

Cómo se apoyan simplemente usando una llanura Data- * atributo, no tan fría como un cierre, pero ..

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')); 
} 
Cuestiones relacionadas