7

Ich habe einen dreistufigen Prozess, der vollständig auf JavaScript und Ajax angewiesen ist, um Daten zu laden und den Prozess von einem Schritt zum nächsten zu animieren. Um die Sache noch komplizierter zu machen, wird der Übergang (vorwärts und rückwärts) zwischen den Schritten animiert :-(. Wenn der Benutzer durch den Prozessanker läuft, werden der aktuelle Schritt und die vorherigen Schritte angezeigt. Wenn er auf einen vorherigen Schritt klickt, wird er zurück zu der vorherige SchrittWie Hinzufügen von Ereignishandler mit Argumenten zu einem Array von Elementen in Javascript?

Derzeit funktioniert der gesamte Prozess (vorwärts und rückwärts) ordnungsgemäß, wenn Sie mit Schritt 1 beginnen, aber wenn Sie direkt zu Schritt 3 springen, führen die Anker für Schritt 1 und Schritt 2 ebenfalls dasselbe aus Aktion als Schritt 3.

Dies ist der Teil des Codes, der alle Schritte bis zum aktuellen Schritt durchläuft, auf dem der Benutzer aktiv ist, und zeigt jeden Anker der Reihe nach an und weist dem Klickereignis die entsprechende Funktion zu:

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

Ich weiß, dass das Problem in der Art und Weise liegt, dass die Aktion und dao_id Parameter übergeben werden. Ich habe auch versucht, profile.steps [i] .action und profile.steps [i] .dao_id aber in In diesem Fall sind sowohl Profil als auch ich oder zumindest ich außerhalb des Bereichs.

Wie mache ich es so, dass ich die Parameter für Aktion und dao_id für jeden Schritt richtig zuweisen kann? (Wenn es einen Unterschied macht, verwenden wir Prototype und Scriptaculous)

Antwort

7

Ihre Verschlussbereichskette verursacht Ihre Probleme. Wenn Sie die Handler-Funktion inline deklarieren, haben Sie eine Schließung erstellt. Offensichtlich hast du das getan, um die Schleife auszunutzen.

Da Sie jedoch eine Schließung erstellt haben, spielen Sie nach den Scoping-Regeln für den Abschluss. Diese Regeln geben an, dass die lokalen Variablen innerhalb der übergeordneten Funktion so lange aktiv und verfügbar bleiben, wie der Abschluss vorhanden ist.

Sie versuchen, "action" und "dao_id" an Ihre Schließung zu übergeben und dann zu verwenden, aber Sie übergeben hier Referenzen, keine Werte. Wenn Ihre Closures (Handler) aufgerufen werden, verwenden sie den Wert, dem die Referenz zuletzt zugewiesen wurde. In Ihrem Fall der Schritt 3-Handler.

Closure-Scoping-Regeln sind verwirrend genug, aber Sie können auch durch die Tatsache verwirrt sein, dass "action" und "dao_id" noch am Leben sind, obwohl der Schleifenblock fertig ausgeführt wurde. Nun, in JavaScript gibt es keinen Blockbereich. Sobald Sie eine Variable deklariert haben, ist sie bis zum Ende der Funktion verfügbar oder bis sie gelöscht wird. Welches auch immer zuerst kommt.

Alles, was gesagt wird, müssen Sie die Umfang Kette zu brechen. Es gibt zwei Möglichkeiten, das zu tun:

Versuchen Sie folgendes:

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

Oder diese:

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

Es scheint fast zu tun, was ich brauche :-(Aber jetzt bewirkt, dass es um das Ereignis fire zweimal und es entlädt sich automatisch automatisch –

+0

Stellen Sie zuerst sicher, dass Sie die Schleife nur einmal aufrufen.Was meinst du mit "Entlädt sich"? Dass das Ereignis nicht erneut ausgelöst wird? – Benry

+0

Ich wünsche nur, dass ich hatte mehr Upvotes ... Danke eine Tonne.Es ist mir jetzt peinlich zu denken, wie lange ich mir den Kopf zerbrochen habe, um das herauszufinden. –

0

Denken Sie zunächst an Ihren Ausführungsbereich im click-Ereignis. Das dieses Schlüsselwort in diesem Kontext bezieht sich auf das Element, auf das geklickt wird. Gibt es eine Möglichkeit, die dao_id aus dem angeklickten Element zu ermitteln?