2011-12-26 11 views
5

Tengo un bucle for en ejecución en javascript. En este ciclo, estoy creando un elemento de lista y lo ato un evento de clic. Cuando hago clic en este elemento de la lista, quiero que llame a una función con los datos del objeto de bucle actual como parámetro.bucle Javascript con evento de clic enlazado que siempre devuelve el último resultado

El problema es que no importa en qué elemento de la lista haga clic. Los datos que se pasan como parámetro son el último elemento del objeto que estoy bucle en lugar del actual en el que se hace clic.

for(e in data) { 

    var suggestItem = $('<li>'+ data[e]['name'] +'</li>'); 

    suggestItem.click(function() { 
     $(this).addClass('activeSuggestion'); 
     suggestSelect(suggestField, data[e]);  
    }); 

    suggestList.append(suggestItem); 

} 

creo que entiendo por qué sucede esto, pero no está seguro de cómo debería manejarlo.

+1

posible duplicado de [jQuery Event Handler creado en el bucle] (http://stackoverflow.com/questions/7774636/jquery-event-handler-created-in-loop) – Pointy

Respuesta

3

Tiene que romper el cierre sobre e.

Dado que está utilizando jQuery, la manera más fácil sería guardar el valor actual de e con la función data de jQuery. Como todos los parámetros de función en JavaScript se pasan por valor, esto efectivamente rompe el cierre; ahora su manejador de clics funcionará con el valor de e cuando se creó el controlador, y no el valor e cuando finaliza el ciclo.

for(e in data) { 

    var suggestItem = $('<li>'+ data[e]['name'] +'</li>'); 

    suggestItem.data('savedE', e).click(function() { 
     $(this).addClass('activeSuggestion'); 
     suggestSelect(suggestField, data[$(this).data('savedE')]); 
    }); 

    suggestList.append(suggestItem); 

} 
+0

Eso hizo el truco. Gracias –

+0

@JustinCarlson - ¡placer - buena suerte! –

5

Esta es una pregunta clásica de cierre de Javascript. Cuando se activa el evento click (cuando haces clic en algo), el ciclo ya ha terminado de ejecutarse. El valor de e es el que sea la última clave en data. La solución al problema es crear un nuevo alcance dentro de su ciclo.

for(var e in data) { 
    (function(datum) { 
     suggestList.append(
      $('<li>' + datum.name + '</li>') 
      .click(function() { 
       $(this).addClass('activeSuggestion'); 
       suggestSelect(suggestField, datum);  
      }); 
     ); 
    })(data[e]); 
} 

Javascript tiene una función de ámbito, por lo que siempre que se encuentre una nueva función, se creará un nuevo ámbito. El código anterior "atrapa" el valor de data[e] en datum porque lo pasa como un parámetro a la función. Otra manera de codificar lo que puede ser menos confuso:

for(var e in data) { 
    (function() { 
     var datum = data[e]; 
     suggestList.append(
      $('<li>' + datum.name + '</li>') 
      .click(function() { 
       $(this).addClass('activeSuggestion'); 
       suggestSelect(suggestField, datum);  
      }); 
     ); 
    })(); 
} 

No pasa un parámetro a la función, sino porque es la función Javascript de ámbito, cada vez que el evento click se dispara buscará donde datum fue asignado.

También tenga en cuenta el for(VAR e in data) que impedirá que e se convierta en una variable global.

Cuestiones relacionadas