• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

.addEventListener innerhalb einer Schleife

samidm

New member
Hallo Zusammen,

was Javascript angeht, bin ich noch ganz am Anfang. Aus diesem Grund komme ich bei meinem Code nicht weiter:

HTML:
<html>
	<head>
    	<title>DOM</title>
        <script type="text/javascript">
           window.onload = function() {
                var basis = document.getElementById("alles");
                var h3 = document.createElement("h3");
                h3.setAttribute("id", "Ueberschrift");
                textknoten = document.createTextNode("Ueberschrift");
                h3.appendChild(textknoten);
                basis.appendChild(h3);
                
               var ids = []; 
               
               for (var i=1; i<=4; i++) {
                    var img = document.createElement("img");
                    id = "Ball" + i;
                    ids.push(id);
                    img.setAttribute("id", id);
                    img.src = "ball1.gif";
                    basis.appendChild(img);
                }
               
               /*for (var i=0; i < ids.length; i++) {
                   var obj = document.getElementById(ids[i]);
                   console.log(obj);
                   obj.addEventListener("click", function() {change(obj);}, false);
               }*/
               
               var obj1 = document.getElementById("Ball1");
               obj1.addEventListener("click", function() {change(obj1);}, false);
               
               var obj2 = document.getElementById("Ball2");
               obj2.addEventListener("click", function() {change(obj2);}, false);
               
               var obj3 = document.getElementById("Ball3");
               obj3.addEventListener("click", function() {change(obj3);}, false);
               
               var obj4 = document.getElementById("Ball4");
               obj4.addEventListener("click", function() {change(obj4);}, false);
           }
            
            function change(a) {
                a.src = "ball2.gif";
            }
             
        </script>
    </head>
    <body id="alles">
    </body>
</html>

Mein Problem ist: Wenn ich den oben aufgeführten Code ausführe, dann klappt alles wunderbar. Es tauchen vier rote Bälle auf, und wenn ich auf einen draufklicke dann wird dieser Ball durch einen Blauen ausgetauscht. Wenn ich aber den auskommentierten Block wieder aktiviere und natürlich den Teilcode unter der Schleife auskommentiere, dann passiert folgendes --> Egal auf welchen Ball ich draufklicke, wird nur der letzte geändert. Wieso??? Eigentlich mache ich doch nichts anderes wie den vorherigen aktivierten Code in eine Schleife zu verpacken. Oder??? Wäre wirklich dankbar für eure Hilfe.
 
Du bist über einen klassischen Stolperstein von JS gefallen. Die anonyme FUnktion, die du bei .addEventListener verwendest, speichert nicht den aktuellen Wert der Variable obj, sondern die Variable selbst. Wenn du also im nächsten Schleifendurchgang die Variable obj neu belegst, ist das auch in der vorher erzeugten anonymen Funktion der Fall.

Es gibt einige Wege, dieses Problem zu umgehen. Die geläufigste ist, dass man einen separaten Funktionsscope erzeugt, der dann den aktuellen Wert speichert:
Code:
               for (var i=0; i < ids.length; i++) {
                   var obj = document.getElementById(ids[i]);
                   console.log(obj);
                   obj.addEventListener(
                   	"click",
                   	(function(obj){
                   		return function() {change(obj);};
                   	}(obj)),
                   	false
                   );
               }
Hier würde sich aber auch noch anbieten, .forEach() zu verwenden:
Code:
ids.forEach(function(id){
	var obj = document.getElementById(id);
	console.log(obj);
	 obj.addEventListener("click", function() {change(obj);}, false);
});

Aber deinen Code kann man noch um einiges vereinfachen, da das Array komplett unnötig ist (und wenn man da ein Array haben will, sollte man gleich die Nodes und nicht IDs speichern) - und damit auch ganzen IDs und document.getElementById()-Aufrufe:
Code:
window.onload = function(){
	var basis = document.getElementById("alles");
	var h3 = document.createElement("h3");
	h3.setAttribute("id", "Ueberschrift");
	textknoten = document.createTextNode("Ueberschrift");
	h3.appendChild(textknoten);
	basis.appendChild(h3);
	
	for (var i = 1; i <= 4; i += 1) {
		var img = document.createElement("img");
		img.src = "ball1.gif";
		basis.appendChild(img);
		img.addEventListener(
			"click",
			function(){
				change(this);
			},
			false
		);
	}
}

function change(a) {
	a.src = "ball2.gif";
}
Wobei hier das change(this) zu beachten ist, das dein vorheriges Problem komplett umgeht. In einem Eventlistener ist der Context (das this) immer die Node, auf dem der Listener registriert ist. Dadurch brauchst du die Verrenkungen mit dem zusätzlichen Funktionsscope gar nicht machen.
 
Aha, ich habe mir schon gedacht sich irgendwo hier der Fehler verbirgt. Auf jeden, vielen, vielen Dank. Super erklaerung.
 
Zurück
Oben