2012-06-01 9 views
5

En el siguiente código verá que estoy tratando de definir un controlador de eventos para image.onclick que toma parámetros adicionales, yo estaba declarando esos parámetros dentro del tiempo loop que espera el alcance definido por javascript de esta manera, pero no es así. Básicamente, todos los controladores de eventos aquí están obteniendo el último valor que doy a las variables id y section_id. ¿Alguna idea sobre cómo manejar una situación en la que quiero generar estos manejadores de forma dinámica?Javascript - Emitir con alcance y pasar parámetros al controlador de eventos creado dinámicamente

function handlePicturesResult(){ 
    if (req.readyState == 4) { // Complete 
     if (req.status == 200) { // OK response 

      var el = document.getElementById('pictureHolder'); 
      while(el.hasChildNodes()){ 
       el.removeChild(el.lastChild); 
      } 

      var tempObject = JSON.parse(req.responseText); 
      var pictures = tempObject.images; 
      var i=0; 

      while(i<pictures.length){ 

       var picIndex = i; 

       var image= new Image(120,80); 
       image.src = 'images/' + pictures[i].url; 
       image.width = 120; 
       image.height = 80; 
       var id = pictures[picIndex].id; 
       var section_id = pictures[picIndex].sectionId; 
       image.onclick = function(event){ 
        deleteImage(event,id,section_id); 
       } 


       var txtNode = document.createTextNode(pictures[picIndex.valueOf()].id); 
       el.appendChild(image); 
       el.appendChild(txtNode); 
       i++; 
      } 
     } else { 
     alert("Problem: " + req.statusText); 
     } 
    } 

} 

Respuesta

13

Sin embargo, otro problema resuelto por closures!

image.onclick = function(id, section_id){ 
    return function(event) { 
     deleteImage(event,id,section_id); 
    } 
}(id, section_id); 

La función exterior se ejecuta a la vez (notar los paréntesis con argumentos al final), y devuelve la función interna, que mantiene en su alcance una copia de las variables ya que están en esa iteración del bucle

JavaScript pasa variable no objeto por valor, por lo que al pasar id y section_id a la función externa, crea una copia de ellos dentro de esa función. Cuando crea y devuelve la función interna, esa función interna mantiene dentro del alcance todas las variables que están en el alcance en el momento de su creación (esto es el corazón de what a closure is), incluidas las copias de variables locales de id y section_id. La función interna, con su alcance único, se convierte en el controlador de eventos para ese elemento.

+0

gracias por toda su ayuda! – flips

+0

lo siento, no sabía cómo hacerlo ahora :) – flips

0

Tiene que usar un cierre. https://developer.mozilla.org/en/JavaScript/Guide/Closures

image.onclick = function(id, s_id){ 
    return function(event){ 
    deleteImage(event, id, s_id); 
    } 
}(id, section_id) 

Alcance en javascript puede definirse dentro de las llaves de una función, que por qué tener una función externa ejecutar con argumentos que se le pasan preservará el valor de estas variables en el momento específico en el bucle que los necesito

Sin ellos, los valores de id y section_id siempre harán referencia al valor que tienen en la última iteración.

0

Este es un problema clásico de JavaScript que se debe a una falta de comprensión sobre el alcance de la función. En esta línea:

deleteImage(event,id,section_id); 

no hay ninguna razón por la que los parámetros pasados ​​a deleteImage deben conservar los valores que tenían en el momento cuando se creó la devolución de llamada. Las variables id y section_id están sujetas al alcance de handlePicturesResult; son variables que existen dentro de ese espacio, y solo hay una sola copia de cada uno. Por lo tanto, cuando se ejecute la devolución de llamada, usará esas variables específicas y los valores a los que se refieren actualmente (a partir de la última iteración del ciclo).

La solución es colocar las variables en un ámbito que "guarde" sus valores en cada iteración del ciclo. Las funciones proporcionan los únicos ámbitos de este tipo en JS. No repetiré las excelentes soluciones ya provistas. Una alternativa es el uso de jQuery de each de iteraciones, y usted no tendrá este problema de nuevo:

$.each(pictures, function(i, picture) { 

    var image= new Image(120,80); 
    var id = pictures.id; 
    var section_id = picture.sectionId; 
    var txtNode = document.createTextNode(id); 

    image.width = 120; 
    image.height = 80; 
    image.src = 'images/' + picture.url; 

    image.onclick = function(event){ 
     deleteImage(event, id, section_id); 
    } 

    el.appendChild(image); 
    el.appendChild(txtNode); 

}); 
  • Asume pictures es una matriz.
Cuestiones relacionadas