addEventListener mit Parametern / Parameter falsch

  • Hi Leute,


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

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


    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
    1. function r_on_out(id)
    2. {
    3. alert(id);
    4. }


    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
    1. 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
    1. st_list = document.getElementsByClassName('vi_set');
    2. for(var i=0; i<st_list.length; i++)
    3. {
    4. window['func_mouseout'+i] = r_on_out(i);
    5. st_list[i].addEventListener('mouseout', window['func_mouseout'+i], false);
    6. }


    damit ich es in einer anderen Funktion dann mit removeEventListener

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


    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?

  • Ach so, ich hatte dies übersehen:

    JavaScript
    1. 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
    1. 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
    1. st_list = document.getElementsByClassName('vi_set');
    2. for(var i=0; i<st_list.length; i++)
    3. {
    4. window['func_mouseout'+i] = function(idx) {return function() {r_on_out(idx)};}(i);
    5. st_list[i].addEventListener('mouseout', window['func_mouseout'+i], false);
    6. }


    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 ).

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


    Einfach ein Array benutzen: