• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Falsches Objekt feuert Event

NetAktiv

Senior HTML'ler
Hallo,

in einem Dokument habe ich ein paar Links mit folgendem Aufbau:
<a id='a1' href='ref_a'><img href='ref_i'>Linktext</a>

Ich wollte den onclick-Event abfangen und dann etwas mit den Attributen des Links tun, daher ordnete ich zu:

document.getElementById('a1').onclick = MyClick;

wobei es im Test erst mal so aussah.
function MyClick(evt) {
evt=evt||window.event;
var oElement = evt.srcElement || evt.target;
alert(oElement.nodeName + '\n' + oElement.href);
}

Sehr verwundert war ich dann über das Ergebnis. Klickte ich auf den Linktext, so gab es das erwartete Ergebnis A/ref_a. Klickte ich dagegen auf das Bild, so gab es das Ergebnis IMG/ref_i. Es sieht so aus, als würde das A-Objekt seinen Event an das eingebettet IMG-Objekt vererben. Klar, ich kann mir schon beim setzen des Events den Inhalt von allen A's merken und durchnummerieren und den onklick-Event mit der entsprechenden Nummer x aufrufen:

document.getElementById('a1').onclick = 'MyClick(x)';

Aber ich würde gerne verstehen, was beim Test hier genau passiert.
Grüße, Rainer
 
Hallo, ich bin davon ausgegangen, dass ich dann das gleiche komische Ergebnis bekomme, nämlich das 'this' dann auf das Image zeigt und nicht den Anker. Tests haben aber gezeigt, dass dem nicht so ist, allerdings ist die Syntax etwas anders, damit es funktioniert. Korrekt ist:

Code:
 MyAnchor.onclick =  function () { MyClick(this); }

Noch Komplexer wäre mein vorgeschlagener Workarround, der hätte mit einer Laufvariablen i wie folgt ausgesehen:
Code:
 eval( 'MyAnchor.onclick = function () { MyClick(' + i + '); }')

Nun haben wir einen eleganten Workarround, unklar ist aber immer noch, warum beim ersten Ansatz das Event Sourceelement auf das IMG und nicht den Anker zeigt, obwohl die onclick-Methoden ausschließlich auf den Links definiert wurden.
 
Zuletzt bearbeitet:
Das Problem kenne ich nur all zu gut :)
Dieses Verhalten nennt man Bubbling.
Das Verhalten des onclicks wird auf alle kindelemente angewandt. Wenn nur dein Link (also <a>) betroffen werden soll musst du das bubbling ausstellen.
schau dir mal folgenden link an:
JavaScript: 9.6 Event-Bubbling
 
öhm, event.target ist einfach nicht das was du dazu brauchst.
Wenn du einen Eventlistener benutzt, ist this das HTMLElement, das das Event, das definiert wurde und nicht das Kindelement.

PHP:
document.getElementById("a1").onclick = function() {
   alert(this.nodeName + '\n' + this.href);
};
// besser:
var a1ClickEvent = function() {
  alert(this.nodeName + '\n' + this.href);
};
if (document.addEventListener) {
  document.addEventListener("click", a1ClickEvent, false)
} else if (document.attachEvent) {
  document.attachEvent("onclick", a1ClickEvent);
}
 
Hallo Gilles, das Bubbling macht ja auch Sinn, damit der Anker beim Klick auf das Bild auch reagiert. Man muss halt nur wissen, dass im Event-Objekt die Original Source evt.srcElement steht und nicht das Element, das den Ereignishandler aufgerufen hat.

@Asterixus: Wenn ich mit this arbeite, dann reicht ja der Vorschlag von threadi, der deiner ersten Zeile entspricht. Warum ist deine nächste Variante als 'besser' gekennzeichnet? Für mich sieht es nur komplizierter aus :-).
 
Besser aus zwei Gründen:
- Es ist der Standard (zumindest addEventListener).
- Man kann damit mehrere Callbacks für einen Eventtypen definieren.

Außerdem ist threadis Art es zu handhaben nicht sauber. Man sollte soweit wie möglich verhindern, dass Eventlistener im HTML definiert werden.
 
So stimmt es nicht

Hallo Asterixus, das mit den mehreren Funktionen auf einen Event leuchtet als Vorteil ein. Es ist aber nicht richtig, dass der Attached Event anders reagiert, also der durch onclick im JavaScript beigefügte. Beide erhalten als Parameter ein Event-Object und die Event-Source ist das geklickte Element, also das Image. Ich habe nun diese Lösung gewählt
HTML:
MyAnchor.onclick =  function () { MyClick(this); }
Diese Lösung hat einfach ein paar Vorteile:
  • Sie gibt mit immer einen Verweis auf den Anker
  • Ich brauch nur einen Eventhandler beim Click
  • Klappt für alle Browser
  • Es funktioniert :-)
Grüße, Rainer
 
Ich glaube wir reden aneinander vorbei.
node.addEventListener kann man so oft benutzen wie man will. node.attachEvent ist nur für IE < 9 und ist im Grunde das Gleiche wie node.addEventListener.

Ich habe nie gesagt, dass diese Methode andere Eigenschaften bei einem Callback haben. this ist immer das definierte Element und parameters[0] ist immer das Event-Objekt.
Source, bzw. target ist nur dann wichtig, wenn du wissen willst, welches Element genau das Event ausgelöst hat.

Wenn du MyClick aufrust, hast du nicht die Möglichkeit, das Event-Objekt zu benutzen ohne auf globale Variablen (was unsauber ist) zurückzugreifen.

Ich verstehe einfach nicht, warum du dich dagegen sträubst, es richtig zu machen.
 
Hallo Asterixus, wo steht denn, dass ich das Event-Objekt brauche? Ich wollte immer nur den Anker, der das Click auslöst, egal ob der Benutzer nun den Text oder das Bild anklickt. Das geht sehr einfach mit einem <a onclick="MyClick(this)" href="...">. Dass ich diese Funktion dem Ereignis nun dynamisch über JavaScript zuordne statt statisch über HTML macht es wohl kaum anders oder gar falscher. Davon abgesehen muss man auch mal den Scope sehen. Ich wollte meine verstaubte Homepage etwas aufpeppen und keine gigantische Web-Applikation schreiben. So suche ich funktionierende Lösungen und wenn ich etwas nicht verstehe, versuche ich es zu hinterfragen, allerdings ohne jeden Anspruch, es dann auch in voller Schönheit zu machen.
Grüße, Rainer
 
Hey Rainer,
Ich verstehe hier schon Asterixus Ansatz mit dem addEventListener bzw. attachEvent vs. onclick.
Es hat zwar nichts direkt mit dem Thema zu tun, ist aber dennoch ein guter Hinweis. Denn onclick Events für ein Objekt überschreiben sich gegenseitig.
Ein Beispiel:

Code:
var ele = document.getElementById("element");
ele.onclick = func1;
ele.onclick = func2;

Wenn du nun auf das element klickst wird ausschließlich func2 ausgeführt.
Und jetzt kommen wir zum wesentlichen Punkt wieso man onclick und ähnliche Eventhandler mit Vorsicht genießen sollte:
Sobald du dir ein externes Script rein holst, dass du auf genau dieses Element anwenden willst und es auch onclick verwendet, wird dein ursprünglicher Aufruf überschrieben. Deswegen empfiehlt es sich attachEvent und addEventListener zu benutzen, da man so mehrere click (oder andere Events) auf ein und das selbe Element legen kann. :)
 
Hallo Gilles, diese Vor/Nachteile hatte ich ja auch verstanden und akzeptiert und ich bin froh, dass ich durch diese Diskussion einiges zum Thema Events gelernt habe. Nur waren große Teile für die Lösung des momentan aufgetretenen Problem nicht relevant, die Theorie dazu höre ich dennoch gerne. Mir war ja auch schon beim Erstellen der Frage klar, dass ich relativ einfach eine andere Lösung finde. Ich sträube mich nur dagegen, diese nun als falsch einzuordnen. Sie ist kein Hack, sie wird wohl von den meisten Browsern unterstützt und sie erfüllt meine konkreten Anforderungen.
Grüße, Rainer
 
Die Frage ist, warum du eine Frage stellst und die am wenigsten richtige Antwort wählst.

Ich denke nach wie vor nicht, dass meine Lösung falsch ist, und das hab ich nun oft genug gesagt und auch begründet. Ich habe die Frage gestellt, weil ich das WARUM wissen wollte. Und da war der Bubbling Hinweis genau der Richtige. Mit diesem Wort konnte ich weiter suchen und habe so und durch die Diskussionen mit dir eine Menge zum JavaScript Eventhandling gelernt :D.
 
Zurück
Oben