2016-08-09 17 views
0
var RelevantDiv = document.getElementById("RelevantDiv"); 
for (var i = 0; i < 5; i++) { 
    for (var j = 0; j < 5; j++) { 
     var NewButton = document.createElement("NewButton"); 
     var IdString = "ID" + i + "_" +j; 
     NewButton.onclick = function() { DoStuff(IdString) }; 
     RelevantDiv.appendChild(NewButton); 
    } 
} 

function DoStuff(IdForStuff) { 
    // Does stuff with id 
} 

Das Problem ist, dass jedes Mal, wenn die NewButton.onclick eingestellt ist, dass sie es bis ins Finale IdString setzen die "ID4_4" ist.Funktionen einstellen zu Onclick für Buttons innerhalb von Schleifen mit Strings in HTML/Javascript

+0

In welcher Umgebung laufen Sie? Ist ES2015 verfügbar? Ein einfacher Wechsel von 'var' zu' let' würde helfen, wenn dies der Fall ist. –

+0

@JamesThorpe muss für so viele Browserversionen wie möglich funktionieren. – IntegrateThis

Antwort

1

Ihre zugrunde liegende Problem ist, dass th Die Variable, die innerhalb des onclick Callbacks IdString verwendet wird, hat seine Deklaration hoisted an den Anfang des aktuellen Bereichs, dh die Funktion, in der es ausgeführt wird. Das bedeutet, dass jedes Mal, wenn Sie innerhalb der Schleife sind, dessen Wert überschrieben wird - es ist funktional gleich wie folgt aus:

var IdString; 

var RelevantDiv = document.getElementById("RelevantDiv"); 
for (var i = 0; i < 5; i++) { 
    for (var j = 0; j < 5; j++) { 
     var NewButton = document.createElement("NewButton"); 
     IdString = "ID" + i + "_" +j; 
     NewButton.onclick = function() { DoStuff(IdString) }; 
     RelevantDiv.appendChild(NewButton); 
    } 
} 

Sie müssen sicherstellen, dass Sie den richtigen Wert von IdString zu erfassen, wenn Sie es brauchen, das ist typischerweise durch die Verwendung eines Verschlusses getan:

var RelevantDiv = document.getElementById("RelevantDiv"); 
for (var i = 0; i < 5; i++) { 
    for (var j = 0; j < 5; j++) { 
     (function(IdString) { 
      var NewButton = document.createElement("NewButton"); 
      NewButton.onclick = function() { DoStuff(IdString) }; 
      RelevantDiv.appendChild(NewButton); 
     })("ID" + i + "_" +j) 
    } 
} 

Hier schaffen wir eine weitere innere Funktion einen neuen Rahmen zu schaffen, jeden einzelnen IdString Wert zu halten. Es wird dann sofort mit dem richtigen Wert für jede Iteration der Schleifen aufgerufen. IdString wird dann in diesem Abschluss erfasst, und der korrekte Wert wird innerhalb des Rückrufs onclick verwendet.


Alternativ können Sie bind the argument im Moment wissen Sie, was der entsprechende Wert ist:

var RelevantDiv = document.getElementById("RelevantDiv"); 
for (var i = 0; i < 5; i++) { 
    for (var j = 0; j < 5; j++) { 
     var NewButton = document.createElement("NewButton"); 
     NewButton.onclick = DoStuff.bind(null, "ID" + i + "_" +j); 
     RelevantDiv.appendChild(NewButton); 
    } 
} 

Damit entfällt sowohl mit den inneren Funktionen und weisen direkt auf das onclick Ereignis zu einer Kopie die DoStuff Funktion, die das richtige Argument haben wird.

2

Das Problem hier ist, dass, wenn der Handler, den Sie zuordnen, ausgeführt wird, die Schleife bereits alle Iterationen durchlaufen hat und die Variable an diesem Punkt ihren Endstatus hat. Um dies zu vermeiden, müssen Sie eine Sperre verwenden. Es handelt sich um eine selbstausführende Funktion (function() { // code })(), die den aktuellen Zustand der Variablen speichert. Wenn die Variable in der aktuellen Iteration, z. B. State 2, als Argument für die selbstausführende Funktion angegeben wird, speichert der Funktionsumfang diesen Status. Wenn die for-Schleife fortgesetzt wird, ändert sich die ursprüngliche Variable immer noch, aber der Umfang der neuen "inneren Funktion" behält den Wert "gesperrt" bei. Also selbst wenn die Schleife-Variable wird am Ende an seinem vierten Zustand sein, wird die verriegelte Variable im Zustand sein, noch 2.

for (var i = 0; i < 5; i++) { 
    button.addEventListener ("click", function() { 
     // Here, i would normally always be 5 
     (function (lockedIndex) { 
      // This lock will make i the way it should be 
      // You have to use lockedIndex instead of i 
     })(i) 
    }); 
} 

für Ihren Code, würde dies in etwa so aussehen:

var RelevantDiv = document.getElementById("RelevantDiv"); 
for (var i = 0; i < 5; i++) { 
    for (var j = 0; j < 5; j++) { 
     (function (ix, jx) { 
      var NewButton = document.createElement("NewButton"); 
      var IdString = "ID" + ix + "_" +jx; 
      NewButton.onclick = function() { DoStuff(IdString) }; 
      RelevantDiv.appendChild(NewButton); 
     })(i, j) 
    } 
} 

function DoStuff(IdForStuff) { 
    // Does stuff with id 
} 
+1

'i' ist nicht das direkte Problem hier, es ist die Tatsache, dass' IdString' gehisst wird. –

+0

Verwenden Sie dann genau die gleiche Methode für IdString. Ich habe es nur als Beispiel verwendet, es bezieht sich nicht auf das "" in Ihrem Code. – NikxDa

+0

In der Tat, aber Ihre Antwort könnte detaillierter über das Problem sein. –

2

Bemerkenswert, dass Sie nicht solche Probleme haben, wenn Sie let oder const statt var verwenden:

for (let i = 0; i < 5; i++) { 
    for (let j = 0; j < 5; j++) { 
     const NewButton = document.createElement("NewButton"); 
     const IdString = "ID" + i + "_" +j; 
     NewButton.onclick = function() { DoStuff(IdString) }; 
     RelevantDiv.appendChild(NewButton); 
    } 
} 
+0

Und trotzdem wird jede Iteration überschrieben, oder fehlt mir etwas? – NikxDa

+1

Nun, wenn Sie 'var' durch' let' oder 'const' ersetzen, die nicht gehisst sind, verschwindet das Problem. –

Verwandte Themen