Funktion ermittelt selbständig Aufrufparameter
Thomas
- javascript
Hallo, eine Frage an die JS-Experten:
ich habe eine HTML-Datei mit einer längeren Liste an <div>-Elementen nach untrigem Schema.
Jeder dieser <div>-Elemente startet bei onClick eine JS-Funktion ("meinefkt"). Das funktioniert soweit gut. Mich stört aber, dass der HTML-Block in meinen Augen doppelt so groß als nötig ist, da pro <div>-element z.B. "url1" und "text1" doppelt vorkommen. Einmal als Parameter im Funktionsaufruf und einmal als <div>-Elementinhalt.
Gibt es hierfür nicht eine einfache Lösung z.B. mittels DOM, dass die Funktion selber feststellt von welchem <div>-Element sie aufgerufen wurde und die entsprechende "url" und "text" auswählt? Ich somit die Funktion ohne Parameter aufrufen kann?
<script language="javascript">
function meinefkt(url, text) {
...
</script>
<div onClick="meinefkt('url1', 'text1')"><img src="url1">text1</div>
<div onClick="meinefkt('url2', 'text1')"><img src="url2">text2</div>
<div onClick="meinefkt('url3', 'text1')"><img src="url3">text3</div>
Hi,
Gibt es hierfür nicht eine einfache Lösung z.B. mittels DOM, dass die Funktion selber feststellt von welchem <div>-Element sie aufgerufen wurde und die entsprechende "url" und "text" auswählt? Ich somit die Funktion ohne Parameter aufrufen kann?
Ja - wenn du die Funktion nicht per HTML-Attribut, sondern per JavaScript als Eventhandler ans jeweilige Element bindest.
referenzAufDIVElement.onclick = deineFunktion;
Für mehrere Elemente natürlich praktischerweise in einer Schleife zugewiesen.
Dann hast du innerhalb der Funktion über this Zugriff auf das Element, auf dem der Event ausgelöst und abgefangen wurde.
Und kannst von dort, über childNodes o.ä., bis zu den Nachfahrenelementen runter steigen und deren Inhalt/Attribute auslesen.
MfG ChrisB
Ein zweiter Punkt der mir noch wichtig wäre:
die Anordnung der <div>-Elemente sollte flexibel bleiben. Ich möchte also ohne größere "Umschreiben" des Codes mal ein <div> entfernen, hinzufügen oder die Reihenfolge ändern.
Ich denke mir es wäre daher eher nicht geeignet, dass ich die <div> zwecks DOM mit einer fixen ID bezeichne.
Ist dies daher für deinen Vorschlag überhaupt nötig, oder soll ich die <div> per "getElementsByTagName()" ansprechen?
Bin eher ein "interessierter JS-Laie", wäre daher ev. über die ein- oder andere Zeile des konkreten Codes dankbar, wie du ihn dir vostellst, damit ich das besser mit SelfHTML nachvollziehen kann, danke.
Hi,
Ein zweiter Punkt der mir noch wichtig wäre:
die Anordnung der <div>-Elemente sollte flexibel bleiben. Ich möchte also ohne größere "Umschreiben" des Codes mal ein <div> entfernen, hinzufügen oder die Reihenfolge ändern.
Kein Problem.
Ich denke mir es wäre daher eher nicht geeignet, dass ich die <div> zwecks DOM mit einer fixen ID bezeichne.
Dann lass IDs weg, wenn du keine Notwendikeit siehst, eine zu vergeben.
Ist dies daher für deinen Vorschlag überhaupt nötig, oder soll ich die <div> per "getElementsByTagName()" ansprechen?
Beispielsweise, ja.
Ggf. auch auf einem übergeordneten Element aufgerufen, wenn nur DIV-Elemente innerhalb eines bestimmten Bereiches/Containerelements überhaupt in Frage kommen.
Bin eher ein "interessierter JS-Laie", wäre daher ev. über die ein- oder andere Zeile des konkreten Codes dankbar, wie du ihn dir vostellst, damit ich das besser mit SelfHTML nachvollziehen kann, danke.
Stichworte: getElementsByTagName, (for-)Schleife, Zuweisung des Eventhandlers wie schon beschrieben.
Probieren & zeigen :-)
MfG ChrisB
Ok,
hier mal ein erster Vorschlag, so wie ich das verstanden habe, möglicherweise noch mit kleineren oder größeren Syntaxfehlern ;-)
<script language="javascript">
divAnz = document.getElementsByTagName("div").length;
for (var i = 1; i <= divAnz; i++)
document.getElementsByTagName("div")[i].onklick = Meinefkt();
function Meinefkt() {
url = this.childNodes[0].src;
text = this.childNodes[0].nodeValue;
...
}
</script>
<div><img src="url1">text1</div>
<div><img src="url2">text2</div>
<div><img src="url3">text3</div>
Hallo,
Verbesserungsvorschlag:
<script language="javascript">
var divs = document.getElementsByTagName("div");
for (var i=0, len = divs.length; i < len; i++)
divs[i].onklick = Meinefkt();
Es reicht, wenn du die div-Collection einmalig holst, also nicht x mal die ganze Liste neu zusammenstellen, nur jedes mal auf ein Element zuzugreifen.
Indizes fangen in JS meist mit 0 an, nicht mit 1.
Gruß, Don P
Hallo,
Meine Verbesserung hat aber auch noch Fehler (von dir übernommen).
Ein Eventhandler namens onklick existiert z.B. nicht, und die korrekte Syntax für for-Schleifen ist
for(...){...}
Ohne die geschweiften Klammern geht's nicht.
Gruß, Don P
aktualisierter Code:
<script type="text/javascript">
var divAnz = document.getElementsByTagName("div").length;
var divs = document.getElementsByTagName("div");
for (var i = 0; i < divAnz; i++) {
divs[i].onClick = Meinefkt;
}
function Meinefkt {
url = this.childNodes[0].src;
text= this.childNodes[0].nodeValue;
...
}
</script>
<body>
<div><img src="url1">text1</div>
<div><img src="url2">text2</div>
<div><img src="url3">text3</div>
</body>
– Ein http://de.selfhtml.org/javascript/sprache/eventhandler.htm@title=Event-Handler onClick exitiert in JavaScript auch nicht.
– Du ermittelst die Collection der Divs immer noch zweimal. Einmal reicht wie gesagt. Immerhin hat der Browser Arbeit damit, alle Divs zu finden in in eine Liste zu stellen. Warum lässt du ihn den Job zweimal hintereinander machen? Zur Übung oder zur Strafe ;) ?
Gruß, Don P
naja, jetzt hab ich da etwas Hirnschmalz reingesteckt, da darf der Browser auch ein bischen rauchen nebenbei ;-)
Ich habe die Lösung ausprobiert, debugt und sie funktioniert jetzt zur vollsten Zufriedenheit. Vielen Dank an alle für ihre wertvollen Tips!!
<body>
<div><img src="url1">text1</div>
<div><img src="url2">text2</div>
<div><img src="url3">text3</div>
</body>
<script type="text/javascript">
var divs = document.getElementsByTagName("div");
var divAnz = divs.length;
for (var i = 0; i < divAnz; i++) {
divs[i].onclick = Meinefkt;
}
function Meinefkt() {
var url = this.childNodes[0].src;
var text= this.childNodes[1].nodeValue;
}
</script>
P/S: Ich mußte das Skript hinter den HTML-Teil platzieren, da das Skript sonst 0 <div>-Elemente zählt. Ist das ok, hat das Nachteile, bzw. gibt es auch eine Lösung, mit der ich das Skript im <head>-Bereich der Datei platzieren kann?
Hallo,
Gratuliere. So sieht's gut aus.
P/S: Ich mußte das Skript hinter den HTML-Teil platzieren, da das Skript sonst 0 <div>-Elemente zählt. Ist das ok, hat das Nachteile, bzw. gibt es auch eine Lösung, mit der ich das Skript im <head>-Bereich der Datei platzieren kann?
Um das HTML sauberer zu halten, empfehle ich aber die Einbindung des Scripts als separate Datei über <script src="...">. Das kann auch unten im HTML stehen, muss nicht zwingend in den Header.
Es gibt auch eine Lösung im head, aber beides hat Vor- und Nachteile. Solange keine Notwendigkeit besteht, kannst du es ruhig am Ende stehen lassen. Wenn die Page später wesentlich mit Javascript-Funktionalität erweitert werden soll, ist es vielleicht sinnvoll, alls Scripts im head unterzubringen und mit dem onload-Handler einzubinden. Dann muss man aber Maßnahmen treffen, damit kein Konflikt mit anderen Scripts (Frameworks oder was immer) entsteht, die in der Regel auch den onload-Handler benutzen.
Gruß, Don P
[latex]Mae govannen![/latex]
Wenn die Page später wesentlich mit Javascript-Funktionalität erweitert werden soll, ist es vielleicht sinnvoll, alls Scripts im head unterzubringen
Das blockiert den Ladevorgang der Seite, bis der Browser alle Scripts geparst hat. Daher sollte Javascript möglichst immer am Ende eingebunden werden. Oft entfällt dann sogar die Notwendigkeit, onload nutzen zu müssen.
Stur lächeln und winken, Männer!
Kai
[latex]Mae govannen![/latex]
function Meinefkt() {
var url = this.childNodes[0].src;
var text= this.childNodes[1].nodeValue;
}
Achtung!
Das funktioniert nicht immer so, wie du es dir vorstellst, nämlich dann, wenn du beispielsweise Zeilenumbrüche einfügst, ändert sich der Index, da Zeilenumbrüche mitgezählt werden (außer in (manchen?) IE):
~~~html
<div id="foo1"><img src="url1">text1</div>
<div id="foo2">
<img src="url1">
text1
</div>
<script type="text/javascript">
alert(document.getElementById('foo1').childNodes.length)
alert(document.getElementById('foo2').childNodes.length)
</script>
Dann müßtest du die gewünschten Kinder auf andere Art ermitteln.
P/S: Ich mußte das Skript hinter den HTML-Teil platzieren, da das Skript sonst 0 <div>-Elemente zählt. Ist das ok, hat das Nachteile, bzw. gibt es auch eine Lösung, mit der ich das Skript im <head>-Bereich der Datei platzieren kann?
Im Head müßtest du die Abarbeitung per onload-Eventhandler starten, wenn der Browser das Dokument eingelesen und den Elementbaum erstellt hat. Vorher kann er die divs logischerweise noch nicht kennen.
Es spricht aber nichts dagegen, das Script am Ende einzubinden, oder noch besser in eine eigenständige Javascript-Datei auszulagern, die dann wiederum vor dem schließenden </body>-Tag (aus oben genannten Gründen) aufgerufen wird.
Stur lächeln und winken, Männer!
Kai
Achtung!
Das funktioniert nicht immer so, wie du es dir vorstellst, nämlich dann, wenn du beispielsweise Zeilenumbrüche einfügst, ändert sich der Index, da Zeilenumbrüche mitgezählt werden (außer in (manchen?) IE):
<div id="foo1"><img src="url1">text1</div>
<div id="foo2">
<img src="url1">
text1
</div>
<script type="text/javascript">
alert(document.getElementById('foo1').childNodes.length)
alert(document.getElementById('foo2').childNodes.length)
</script>
>
> Dann müßtest du die gewünschten Kinder auf andere Art ermitteln.
Und was wäre hier eine geeignete Methode? Kann man z.B. generell auf das 1.<img>-Child (unabhängig von Zeilenumbrüchen oder anderen childs davor) zugreifen?
Und was wäre hier eine geeignete Methode? Kann man z.B. generell auf das 1.<img>-Child (unabhängig von Zeilenumbrüchen oder anderen childs davor) zugreifen?
Ja, mit getElementsByTagName ausgehend von einem Elementknoten:
var img = element.getElementsByTagName('img')[0];
Mathias
Hi,
[...] und die korrekte Syntax für for-Schleifen ist
for(...){...}
Ohne die geschweiften Klammern geht's nicht.
oh doch, ohne die geschweiften Klammern geht's auch - jedenfalls dann, wenn der Schleifenrumpf aus nur einer Anweisung besteht. Insofern war dein Beispiel an der Stelle völlig korrekt.
Trotzdem empfehle ich, die geschweiften Klammern konsequent zu setzen, auch da, wo sie nicht zwingend notwendig sind. Wie leicht vergisst man später, die Klammern zu ergänzen, wenn die Schleife doch zwei oder mehr Anweisungen enthalten soll ...
So long,
Martin
Hallo,
[...] und die korrekte Syntax für for-Schleifen ist
for(...){...}
Ohne die geschweiften Klammern geht's nicht.oh doch, ohne die geschweiften Klammern geht's auch - jedenfalls dann, wenn der Schleifenrumpf aus nur einer Anweisung besteht. Insofern war dein Beispiel an der Stelle völlig korrekt.
Ah ok, das hatte ich verdrängt und gedacht, es ginge wirklich nicht. Für mich gehören die Klammern einfach dazu, wie auch nach if().
Gruß, Don P
[latex]Mae govannen![/latex]
<script language="javascript">
Das language-Attribut ist schon ewigen Zeiten veraltet. Benutze das type-Attribut.
divAnz = document.getElementsByTagName("div").length;
for (var i = 1; i <= divAnz; i++)
document.getElementsByTagName("div")[i].onklick = Meinefkt();
Das entspricht nicht dem Beispiel von Chris. Du hast da zwei Zeichen zuviel. (Verraten sei: hinter dem "=")
Abgesehen davon gibt es kein "onklick".
Und noch Optimierung, die mit der eigentlichen Funktionalität nichts zu tun hat:
Du solltest den Code dahingehend optimieren, daß du _vor_ der Schleife alle Referenzen auf die divs per getElementsByTagName ermittelst und innerhalb der Schleife dann nur noch auf diese Referenzliste zugreifst.
Stur lächeln und winken, Männer!
Kai
divAnz = document.getElementsByTagName("div").length;
for (var i = 1; i <= divAnz; i++)
document.getElementsByTagName("div")[i].onklick = Meinefkt();
Siehe bspw. Grundlagen der Ereignisverarbeitung
Darin auch Häufiger Fehler: Handler-Funktion direkt aufrufen
Mathias