addEventListener mit Parametern / Parameter falsch

  • Hi Leute,


    ich habe ein Problem mit dem Funktionsaufruf in einem addEventListener. Es sieht wie folgt aus:

    JavaScript
    st_list = document.getElementsByClassName('vi_set');
    for(var i=0; i<st_list.length; i++)
    	{
    		st_list[i].addEventListener('mouseout', function() {r_on_out(i)}, false);
    	}


    Dieser Code steht in der window.onload = function() {...} Die st_list ist global, damit ich sie in anderen Funktionen nutzen kann.
    Weiter unten befindet sich die aufzurufene Funktion:

    JavaScript
    function r_on_out(id)
    {
    	alert(id);
    }


    Ich teste hier mit alert, bekomme aber immer das gleiche, falsche Ergebnis.
    Es ist so, es gibt 13 Elemente mit der class "vi_set", die auch richtig erkannt und in der st_list gespeichert werden. Demnach sind es also st_list[0] - st_list[12].
    Beim alert bekomme ich aber jedesmal als Ausgabe "13", egal, welches Element ich gerade nehme (Die Ausgabe sollte ja eigentlich "0" bei Element1, "1" bei Element2 usw. sein)


    Weiß da jemand weiter?

  • Dies ist ein häufiges Problem, wenn man Eventlistener in einer Schleife registriert und dabei den Schleifenindex verwendet. Was passiert, ist folgendes: Der Code in der anonymen Funktion wird ja nicht beim Registrieren ausgeführt, sondern erst, wenn das Ereignis, in diesem Fall das Mouseout, eintritt. Dann ist die Schleife längst durchgelaufen und der Index hat seinen Endwert von 13. Lösung ist folgende:

    JavaScript
    st_list[i].addEventListener('mouseout', function(idx) {return function() {r_on_out(idx)};}(i), false);


    In diesem Fall wird die äußere Funktion sofort aufgerufen, weil auf die Definition ein Klammernpaar folgt. Innerhalb der äußeren Funktion hat der Parameter idx den aktuellen Wert, der in der inneren Funktion verwendet wird. Die äußere Funktion gibt die innere als Returnwert zurück und die innere wird als Listener registriert.

  • Der Code in der anonymen Funktion wird ja nicht beim Registrieren ausgeführt, sondern erst, wenn das Ereignis, in diesem Fall das Mouseout, eintritt. Dann ist die Schleife längst durchgelaufen und der Index hat seinen Endwert von 13.

    Vielen Dank.
    Das zeigt mal wieder, das konzentrierteres Einlesen (z.B. zur Funktionalität von addEventListener) doch wichtig ist.
    Wenn ich deine Antwort jetzt so lese, ist es ja nur logisch, das die gewünschten Werte ja nicht beim eigentlichen Event landen, weil sie zu dem Zeitpunkt längst "verflogen" sind.


    Nochmals Danke.

  • Verdammt, ich habe es gerade alleine versucht und im Netz geschaut, aber ich komme einfach nicht dahinter. Vielleicht habe ich auch einfach nur einen Denkfehler.


    Es geht darum, wie ich removeEventListener richtig aufrufen muss.
    Ich habe versucht bei addEventListener in der Schleife folgendes zu machen:

    JavaScript
    st_list = document.getElementsByClassName('vi_set');
    	for(var i=0; i<st_list.length; i++)
    	{
    		window['func_mouseout'+i] = r_on_out(i);
    		st_list[i].addEventListener('mouseout', window['func_mouseout'+i], false);
    	}


    damit ich es in einer anderen Funktion dann mit removeEventListener

    JavaScript
    ...
    st_list[id].removeEventListener('mouseout', window['func_mouseout'+id], false);
    ...


    wieder entfernen kann. Ich bin gard echt ein bischen durcheinander.
    Im Netz wird empfohlen, wegen removeEventListener eben keine Anonymen Funktionen zu verwenden, da bei addEventListener & removeEventListener dieselben listener verwendet werden müssen?
    Wie soll ich das machen?


    Ich schaue mich weiter nach einer Lösung um, jedoch blicke ich grad echt nicht durch.
    Ist removeEventlistener überhaupt anwendbar, wenn ich die Events wie zuvor angemerk registriere?

  • Wie definierst Du denn

    JavaScript
    window['func_mouseout'+id]

    ?


    [size=10]Möglicher Weise kommt man hier nicht daran vorbei, das ungeliebte eval einzusetzen, um Funktionen der Form myListener1, myListener2 zu erzeugen.

  • Mit

    JavaScript
    window['func_mouseout'+id]


    sollte ich doch func_mouseout1, func_mouseout2 etc. haben. Nur, wie kann ich die denn beim remove wieder angeben?
    Das müsste doch genauso aufgerufen werden können, oder?

  • Ach so, ich hatte dies übersehen:

    JavaScript
    window['func_mouseout'+i] = r_on_out(i);


    Was hier passiert, ist folgendes: Da der Funktionsname r_on_out von einem Klammernpaar gefolgt wird, wird nicht diese Funktion zugewiesen sondern r_on_out wird ausgeführt mit i als Parameter und der Rückgabewert wird zugewiesen. D. h. ganz etwas anderes als das, was Du möchtest.

  • Wie ich schon schrieb: Mit eval kann man Variablen- und Funktionsnamen dynamisch anlegen. Müsste dann so aussehen:


    JavaScript
    st_list[i].addEventListener('mouseout', eval('function listener' + i + '() {r_on_out(' + i + ')}'), false);


    Ich denke mal darüber nach, ob es noch eine bessere Lösung gibt.

  • Ich habe mal folgendes getestet:

    JavaScript
    st_list = document.getElementsByClassName('vi_set');
    	for(var i=0; i<st_list.length; i++)
    	{
    		window['func_mouseout'+i] = function(idx) {return function() {r_on_out(idx)};}(i);
    		st_list[i].addEventListener('mouseout', window['func_mouseout'+i], false);
    	}


    Sowohl addEventListener, als auch removeEventListener klappen damit, jedoch habe ich irgendwie das Gefühl, als würde dieser Code nicht "gut" sein.
    Meinst du, so könnte ich es lassen? Immerhin funktioniert es damit einwandfrei (zumindest nach den ersten kleinen Tests, gerade :D ).

  • Sehr gut, genau das wollte ich auch gerade vorschlagen. Ich bin weder ein Freund von diesem noch von eval aber mir kommt es so vor, dass in dem Fall kein Weg daran vorbei geht, das eine oder das andere zu verwenden, weil man den Funktionsnamen dynamisch aufbauen muss.

  • Jap, zum einen ist die Elementanzahl variabel, zum anderen muss aber jedes einzelne Element separat bearbeitet werden können (add / remove).
    Ich mag dynamische Bezeichnungen auch nicht, jedoch sind sie hier notwendig.

  • Entweder verstehe ich hier das Problem nicht oder die Lösung ist so simpel.


    Einfach ein Array benutzen:


Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!