Sep 2008

Javascript :: Zugriff auf die Knoten des DOM
oder »Das Fischen nach den Knoten«

 
 

Drei Javascript-Methoden des DOM greifen direkt auf ein Element oder eine Gruppe von Elementen zu – sie bedienen sich eines eindeutigen ID-Attributs, des (ebenso eindeutigen) NAME-Attributs oder sammeln alle Elemente mit einem bestimmten Tag-Namen. Dabei werden zwei Methoden auf dem Document-Objekt ausgeführt:

getElementById(elementId) getElementsByName(name)
DOM Core DOM HTML

Eine Methode gehört dem Element-Objekt und kann sowohl für einen Elementknoten node als auch document aufgerufen werden.

getElementsByTagName(tagName)  

An alle Knoten unterhalb eines Element gelangt die Methode childNodes.

document.getElementById(id)

Sucht den Knoten mit dem id-Attribut id.

Am einfachsten ist der direkte Sprung zum Ziel – zu einem Element des document-Knotens mit einem ID-Attribut.

Im Skript
function someDiv()
{
	if (document.getElementById('fix')) {
		document.getElementById('fix').innerHTML = "Hier ist das Element";
		document.getElementById('fix').style.color = "green";
	} else {
		alert('Fehler: Kein Element mit der ID fix gefunden!');
	}
}
HTML-Quelltext
<div id="fix">
</div>

Das Schöne am Zugriff auf Element mit einem ID-Attribut: Wir müssen uns nicht um die Struktur des Dokuments kümmern und keinen Pfad von einem Einstiegselement aus bis zum gewünschten Element finden. Wichtig ist nur die Prüfung, ob ein Element mit der ID 'fix' auch wirklich existiert, damit – falls das Element nicht gefunden wird – kein Javascript-Fehler entsteht, der auch die Ausführung weiterer Funktionen behindern kann.

node.getElementsByTagName(tagName)

gibt ein Sammlung aller Knoten mit dem Namen tagName. Tatsächlich gibt getElementsByTagName() Objekte mit der index- und length-Eigenschaft zurück, aber kein Array, so dass Array-Methoden nicht benutzt werden können. Die length-Eigenschaft liefert die Anzahl der gefundenen Elemente, die index-Eigenschaft gibt Zugriff auf die einzelnen Knoten.

var allH2 = document.getElementsByTagName('h2');
var text = "";
var h2children; 
for (var i=0; i<allH2.length; i++) {
   h2children = allH2[i].childNodes;
   for (var j=0; j<h2children.length; j++) {
      if (h2children[j].nodeType == "3") {
         text = text + h2children[j].nodeValue + "\n";
      }
   }
}
alert(text);

Nach dem Aufruf von var allH2 = document.getElementsByTagName('h2'); sind alle H2-Elemente dieses Dokuments im Array allH2 versammelt. allH2.length ist also die Anzahl der H2-Elemente, so dass die Inhalte der H2-Elemente in der Variablen text gelistet werden können.

Die H2-Elemente sind aber nur die Hülle für die Inhalte und erst die Textknoten unterhalb der H2-Elemente enthalten die Texte, die uns interessieren. Und wer sagt uns, dass der Autor nicht auch noch ein paar Elementknoten wie EM oder BR oder einen Anker <a id=""></a> in die Überschriften gesetzt hat?

Die erste Anweisung im for-Block sammelt alle Kindknoten des jeweiligen H2-Elements im Array h2children. Nur wenn ein Kindknoten ein Textknoten ist – if (h2children[j].nodeType == "3") – wird sein Wert in den Textstring aufgenommen. Der Einfachheit zuliebe unterschlägt das Skript also Inhalte von Elementknoten, die eventuell unter den H2-Elementen hängen.

Wer eher pragmatisch veranlagt ist und den Pfad des reinen DOM kurz verlassen mag, kann die H2-Elemente kurzerhand mit der Eigenschaft innerHTML auslesen.

var allH2 = document.getElementsByTagName('h2');
var text = "";
var h2children; 
for (var i=0; i<allH2.length; i++) {
   text = text + allH2[i].innerHTML + "\n";
}
alert(text);

document.getElementsByName(name)

gibt ein Array aller Knoten mit name-Attribut name.

Das name-Attribut in Formularelementen dient der Kodierung von Namen-/Wertpaaren für die verarbeitende Anwendung und ist in der Regel eindeutig – ähnlich dem id-Attribut. Die Ausnahme bildet INPUT-Elemente vom Typ radio, in denen ein gemeinsames name-Attribut eine zusammengehörige Gruppe von Radiobuttons identifiziert, aber auch ein <input type="submit" name="aName" … /> kann mehrfach im Dokument vorkommen – z.B. als Button „Speichern“ und „Vorschau“.

<form action="jsDOM2.shtm" method="get" id="jsdom2F12">
   <fieldset>
      <p><input type="radio" name="color" value="rot" id="rot" /> Rote Himbeeren
         <input type="radio" name="color" value="gruen" id="gruen" /> Grüne Tomaten
         <input type="radio" name="color" value="blau" id="blau" /> Blaue Pflaumen</p>
      <p><input type="submit" value="Auswerten" /></p>
   </fieldset>
</form>
var cols = document.getElementsByName('color');
for (var i=0; i<cols.length; i++) {
   if (cols[i].checked == true) {
      alert('Ihre Farbe ist ' + cols[i].nextSibling.nodeValue);
      break;
   }
}

Die erste Anweisung liest alle Elemente, in denen name="color" notiert ist, in das Array cols. Der for-Block durchläuft alle gefundenen Elemente und prüft, ob der Radiobutton aktiviert ist (if (cols[i].checked == true)). Die Ausgabe geht davon aus, dass der Text zum Radiobutton direkt auf das INPUT-Element folgt … volles Risiko, denn der Text könnte ebensogut vor dem jeweiligen INPUT-Element stehen oder in den Tiefen einer Layouttabelle versteckt sein.

Die sichere Variante arbeitet mit einem <label>-Tag.

<form action="jsDOM2.shtm" method="get" id="jsdom2F12">
   <fieldset>
      <p><input type="radio" name="color" value="rot" id="rot" />
            <label for="rot">Rote Himbeeren</label>
         <input type="radio" name="color" value="gruen" id="gruen" />
            <label for="gruen">Grüne Tomaten</label>
         <input type="radio" name="color" value="blau" id="blau" />
            <label for="blau">Blaue Pflaumen</label></p>
      <p><label for="wert"><input type="submit" value="Auswerten" id="wert" /></label></p>
   </fieldset>
</form>

Wie zuvor liest die erste Anweisung alle Elemente mit name="color" in das Array cols, anschliessend aber auch noch alle LABEL-Elemente in das Array labs.

var cols = document.getElementsByName('color');
var labs = document.getElementsByTagName('label');
	
for (var i=0; i<cols.length; i++) {
   if (cols[i].checked == true) {
      for (var j=0; j<labs.length; j++) {
         var htmlFor = labs[j].getAttribute('for') ? 
                       labs[j].getAttribute('for') : labs[j].getAttribute('htmlFor');
         if (htmlFor == cols[i].getAttribute('id')) {
            alert('Gewählt wurden ' + labs[j].childNodes[0].nodeValue);
            break;
         } 
      }
      break;
   }
}

Wenn innerhalb der ersten for-Anweisung das eingeschaltete Element vorliegt (if (cols[i].checked == true)), durchläuft die innere for-Anweisung das Array labs bis zu dem Objekt, das ein passendes for-Attribut aufweist. Der Text des <label>-Tags ist der erste Kindknoten des label-Objekts – also labs[j].childNodes[0].nodeValue.

Internet Explorer interpretiert getAttributes('for') auf label-Objekten nicht, wohl aber das antike htmlFor. Um die Methode für IE und moderne Browser zu normalisieren, steht die Ternary-Bedingung.

var htmlFor = labs[j].getAttribute('for') ? labs[j].getAttribute('for') : labs[j].getAttribute('htmlFor');

Sie liest sich: Die Variable htmlFor ergibt sich aus

  1. wenn labs[j].getAttribute('for') ? existiert, dann nehme den Wert von labs[j].getAttribute('for')
  2. sonst nehme den Wert von labs[j].getAttribute('htmlFor')
   


Copyright © 2000 - 2010 Media Engineering Alle Rechte vorbehalten
Design + Programmierung Media Engineering U. Häßler 47506 Neukirchen-Vluyn • Impressum und Nutzungsbestimmungen