2008-11-24 22 views
7

Tengo un proceso de tres pasos totalmente dependiente de JavaScript y Ajax para cargar datos y animar el proceso de un paso al siguiente. Para complicar aún más las cosas, la transición (hacia delante y hacia atrás) entre los pasos está animada :-(. A medida que avanza el usuario a través del proceso, aparecen los delimitadores que muestran el paso actual y los pasos anteriores. Si hacen clic en un paso anterior, los devuelve a el paso anterior.Cómo agregar el controlador de eventos con argumentos a una matriz de elementos en Javascript?

En este momento, todo el proceso (hacia delante y hacia atrás) funciona correctamente, si comienza en el paso 1, pero si pasa directamente al paso 3, los anclajes del paso 1 y 2 también realizan el mismo acción como paso 3.

Esta es la parte del código que recorre todos los pasos hasta el paso actual en el que el usuario estaría y muestra cada anclaje a su vez y asigna la función adecuada al evento click:

for (var i = 0; i < profile.current + 1; i++) { 
    if ($('step_anchor_' + i).innerHTML.empty()) { 
     var action = profile.steps[i].action; 
     var dao_id = profile.steps[i].dao_id; 

     $('step_anchor_' + i).innerHTML = profile.steps[i].anchor; 
     $('step_anchor_' + i).observe('click', function(){ 
      pm.loadData(action, dao_id, true); 
     }); 

     Effect.Appear('step_anchor_' + i, { 
      duration: 1, 
      delay: (down_delay++) 
     }); 
    } 
} 

Sé que el problema radica en la forma en que se pasan los parámetros de acción y dao_id. También he intentado pasar profile.steps [i] .action y profile.steps [i] .dao_id pero en ese caso tanto el perfil como yo o al menos yo estamos fuera del alcance.

¿Cómo lo hago para poder asignar los parámetros de acción y dao_id correctamente para cada paso? (Si hace alguna diferencia, estamos usando Prototype y Scriptaculous)

Respuesta

7

Su cadena de alcance de cierre está causando sus problemas. Al declarar la función del controlador en línea, ha creado un cierre. Obviamente lo hiciste para aprovechar el ciclo.

Sin embargo, dado que ha creado un cierre, está jugando según las reglas de delimitación de cierre. Esas reglas establecen que las variables locales dentro de la función padre permanecen activas y disponibles mientras exista el cierre.

Está tratando de pasar y luego usar "acción" y "dao_id" para su cierre, pero aquí está pasando referencias, no valores. Entonces, cuando se llaman sus cierres (manejadores) usan el valor que la referencia fue asignada por última vez. En su caso, el controlador Paso 3.

Las reglas de delimitación de cierres son bastante confusas, pero también puede confundirse el hecho de que "acción" y "dao_id" sigan vivos aunque el bloque de bucle haya terminado de ejecutarse. Bueno, en JavaScript no existe el alcance del bloque. Una vez que declaras una variable, está disponible hasta el final de la función o hasta que se elimina. Lo que sea que venga primero.

Dicho todo esto, debe romper la cadena de alcance. Aquí hay dos maneras de hacerlo:

Prueba esto:

for (var i = 0; i < profile.current + 1; i++) { 
    if ($('step_anchor_' + i).innerHTML.empty()) { 
     var action = profile.steps[i].action; 
     var dao_id = profile.steps[i].dao_id; 

     $('step_anchor_' + i).innerHTML = profile.steps[i].anchor; 
     $('step_anchor_' + i).observe('click', function(a, b){ 
       return function(){pm.loadData(a, b, true)}; 
     }(action, dao_id)); 

     Effect.Appear('step_anchor_' + i, { 
       duration: 1, 
       delay: (down_delay++) 
     }); 
    } 
} 

O esto:

function createHandler(action, dao_id) { 
    return function(){pm.loadData(action, dao_id, true);}; 
} 

/* snip - inside some other function */ 
for (var i = 0; i < profile.current + 1; i++) { 
    if ($('step_anchor_' + i).innerHTML.empty()) { 
     var action = profile.steps[i].action; 
     var dao_id = profile.steps[i].dao_id; 

     $('step_anchor_' + i).innerHTML = profile.steps[i].anchor; 
     $('step_anchor_' + i).observe('click', createHandler(action, dao_id)); 
     Effect.Appear('step_anchor_' + i, { 
       duration: 1, 
       delay: (down_delay++) 
     }); 
    } 
} 
+0

Parece casi hacer lo que tengo :-(Sin embargo, ahora se hace que el evento a dispara dos veces y simplemente se descarga automáticamente. –

+0

Primero, asegúrate de estar llamando al ciclo solo una vez. Además, ¿a qué te refieres con "se descarga"? ¿Que el evento no vuelva a sonar? – Benry

+0

Solo deseo que tenía más votos ascendentes ... Muchas gracias.Me avergüenza ahora pensar cuánto tiempo me golpeé la cabeza tratando de resolver eso. –

0

Primero, recuerde su alcance de ejecución en el evento click. La palabra clave en ese contexto se refiere al elemento al que se hace clic. ¿Hay alguna forma de que pueda determinar el dao_id del elemento que se hace clic en?

Cuestiones relacionadas