Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 <<   zurück
JavaScript und AJAX von Christian Wenz
Das umfassende Handbuch
Buch: JavaScript und AJAX

JavaScript und AJAX
839 S., mit DVD, 39,90 Euro
Galileo Computing
ISBN 3-89842-859-1
gp Kapitel 16 DOM
  gp 16.1 Der DOM-Baum
  gp 16.2 Navigation im Baum
  gp 16.3 Den Baum modifizieren
    gp 16.3.1 Wichtige Methoden
    gp 16.3.2 Zugriff auf einzelne Elemente
    gp 16.3.3 Zugriff auf Tags
    gp 16.3.4 Beispiele


Galileo Computing

16.3 Den Baum modifizieren  downtop

Der große Vorteil von DOM gegenüber DHTML und den früheren DOM-Implementierungen besteht darin, dass man Elemente nicht nur ändern, sondern auch entfernen und sogar neue Elemente einfügen kann. Die Baumstruktur ist hier von großem Vorteil, da das Löschen eines Knotens nicht die Baumintegrität gefährdet.


Galileo Computing

16.3.1 Wichtige Methoden  downtop

In der folgenden Tabelle sehen Sie eine grobe Übersicht über die verschiedenen Methoden.


Tabelle 16.3     Methoden zur Veränderung des DOM-Baums

Methode Syntax Beschreibung
appendChild Vater.appendChild(Kind) Hängt Kind als Kindknoten an Vater an.
cloneNode Original.cloneNode (alles) Erzeugt einen Knoten, der identisch mit Original ist. Ist alles gleich true, so werden auch alle Kindknoten von Original mit dupliziert; bei false lediglich der Knoten selbst.
createElement document.createElement (HTML-Tag) Erzeugt einen Knoten, der aus dem in Klammern angegebenen HTML-Element (z.  B. h3) besteht.
hasChildNodes Knoten.hasChildNodes() Boolescher Wert, der angibt, ob Knoten Kinder hat oder nicht.
insertBefore Vater.insertBefore(Kind, Schwester) Kind wird als Kindknoten von Vater eingefügt, und zwar direkt vor Schwester.
removeNode Knoten.removeNode(alles) Knoten wird aus dem DOM-Baum entfernt. Ist alles gleich true, dann werden auch alle Kindknoten von Knoten entfernt.
replaceNode Alt.replaceNode(Neu) Der Knoten Alt wird durch den Knoten Neu ersetzt.
setAttribute Knoten.setAttribute( Name, Wert) Der Knoten enthält ein neues Attribut.

In einem kleinen Beispiel soll dies einmal ausprobiert werden. Wir gehen von dem obigen Beispiel-HTML-Dokument aus und bauen die folgenden Effekte ein:

gp  Wenn der Benutzer mit der Maus auf eine der Grafiken klickt, soll diese durch eine andere Grafik ausgetauscht werden.
gp  Wenn der Benutzer noch einmal auf die Grafik klickt, soll sie komplett verschwinden (eine Art armseliges Ballerspiel mit JavaScript also).

Der Einfachheit halber werden die Event-Handler der Grafiken schon im ursprünglichen HTML-Dokument gesetzt. Es muss also nur noch eine Funktion geschrieben werden, die überprüft, ob die Grafik schon einmal angeklickt worden ist, und dann entweder die Grafik austauscht oder den Knoten aus dem DOM-Baum entfernt. Alternative Möglichkeiten des Event-Handlings finden Sie in Kapitel 14.


Galileo Computing

16.3.2 Zugriff auf einzelne Elemente  downtop

Jetzt benötigen Sie nur noch eines: den Startpunkt. Dafür gibt es eine weitere Methode des document-Objekts, und zwar getElementById(). Diese ermöglicht Ihnen den Zugriff auf jedes HTML-Element, solange es nur eine ID besitzt. Diese ID nämlich übergeben Sie als Parameter. So greifen Sie beispielsweise per document.getElementById("alles") auf das <body>-Element zu und können von dort ab alle Kindknoten (sprich: die Elemente der HTML-Seite) erreichen.

Der folgende Code ist kurz und einleuchtend und wird daher ohne längere Vorrede abgedruckt. Er enthält allerdings noch einen kleinen (absichtlichen) Fehler, dazu später mehr.

<html>
<head>
<title>DOM-Demo</title>
<script type="text/javascript"><!--
function mausklick(Nummer){
   var obj = document.getElementById("alles").childNodes[Nummer + 1];
   var gfx = obj.src;
   if (gfx.indexOf("ball.gif") > –1) {
      obj.src="kreuz.gif";
   } else {
      obj.removeNode(false);
   }
}
//--></script>
</head>
<body id="alles">
<h3 id="Ueberschrift">DOM-Demo</h3>
<img src="ball.gif" id="Ball1" onclick="mausklick(1);" />
<img src="ball.gif" id="Ball2" onclick="mausklick(2);" />
<img src="ball.gif" id="Ball3" onclick="mausklick(3);" />
<img src="ball.gif" id="Ball4" onclick="mausklick(4);" />
</body>
</html>

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 16.4     Die DOM-Demo im Internet Explorer

Wie Ihnen sicherlich nicht entgangen ist, spuckt der Browser hin und wieder Fehlermeldungen bei der Ausführung dieses Skripts aus, beispielsweise, wenn Sie auf die dritte Grafik von links klicken. Sehr merkwürdig! Zum Testen sollten Sie in die Funktion mausklick() den folgenden Debug-Code einfügen (am besten gleich am Anfang):

function mausklick(Nummer) {
   var meldung = "";
   for (var i=0; i<document.getElementById("alles").childNodes.length; i++) {
      meldung += document.getElementById("alles").childNodes[i].nodeName + 
"|" + document.getElementById("alles").childNodes[i].nodeType + "\n";
   }
   alert(meldung);
   var obj = document.getElementById("alles").childNodes[Nummer + 1];
   var gfx = obj.src;
   if (gfx.indexOf("ball.gif")>-1) {
      obj.src="kreuz.gif";
   } else {
      obj.removeNode(false);
   }
}

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 16.5     Die Debug-Ausgabe

In Abbildung 16.5 (oder auch im DOM Inspector) sehen Sie die Ursache des Übels: Anscheinend befinden sich zwischen den einzelnen Grafiken noch Textstücke. Auch das ist nicht weiter verwunderlich: Auch wenn ein Zeilenumbruch im HTML-Code in der Anzeige quasi nie Auswirkungen hat, ist das beim DOM-Baum ein Textelement. Sie sollten also die Zeilenumbrüche entfernen, dann gibt es beim ersten Anklicken einer Grafik auch keine Fehlermeldungen mehr.

Um diese Fehlermeldungen zu vermeiden, sollten Sie die HTML-Elemente, die Sie in Ihrem Skript verwenden wollen, mit den oben gezeigten Methoden (createElement(), setAttribute() und appendChild() bzw. insertBefore()) erzeugen. Das obige HTML-Dokument kann auch folgendermaßen erzeugt werden (von der Klick-Funktionalität mal abgesehen):

<html>
<head>
<title>DOM-Demo</title>
<script type="text/javascript"><!--
function init() {
   var basis = document.getElementById("alles");
   var h3 = document.createElement("h3");
   h3.setAttribute("id", "Ueberschrift");
   h3.innerText = "Überschrift";
   basis.appendChild(h3);
   for (var i=1; i<=4; i++) {
      img = document.createElement("img");
      img.setAttribute("id", "Ball" + i);
      img.src = "ball.gif";
      basis.appendChild(img);
   }
}
//--></script>
</head>
<body id="alles" onload="init();">
</body>
</html>

Ein kleiner Vorgriff war dabei: innerText bezeichnet den Text innerhalb eines HTML-Elements. Eine Alternative dazu gibt es auch noch: Der Text innerhalb eines HTML-Elements ist wie bereits gesehen ein Knoten, und zwar ein Textknoten. Mit den DOM-Methoden von JavaScript können Sie auch einen solchen Knoten erzeugen (die dazugehörige Methode heißt document.createTextNode()) und diesen dann in den DOM-Baum einhängen – als Unterknoten des übergeordneten Elements natürlich:

<html>
<head>
<title>DOM-Demo</title>
<script type="text/javascript"><!--
function init() {
   var basis = document.getElementById("alles");
   var h3 = document.createElement("h3");
   h3.setAttribute("id", "Ueberschrift");
   textknoten = document.createTextNode("Überschrift");
   h3.appendChild(textknoten);
   basis.appendChild(h3);
   for (var i=1; i<=4; i++) {
      img = document.createElement("img");
      img.setAttribute("id", "Ball" + i);
      img.src = "ball.gif";
      basis.appendChild(img);
   }
}
//--></script>
</head>
<body id="alles" onload="init();">
</body>
</html>

Wie Sie in einer Aufgabe am Ende des Kapitels jedoch noch sehen werden, ist das ursprüngliche Skript nicht ganz fehlerfrei. Es ist einfach gefährlich, über den Index auf ein Element zuzugreifen, wenn zwischendurch Elemente entfernt werden sollen. Aber Sie haben ja bereits an anderer Stelle schon gesehen, dass es fast immer besser ist, per Identifikator auf ein Element zuzugreifen. Hier ist das auch der Fall – verwenden Sie einfach getElementById() für die einzelnen Bälle. Im folgenden Code finden Sie das für unser kleines Beispiel einmal umgesetzt. Anhand der Nummer, die an mausklick() übergeben wird, kann der Identifikator der angeklickten Grafik ermittelt werden, und dieser Wert wird dann an getElementById() übergeben.

function mausklick(Nummer){
   var obj = document.getElementById("Ball" + Nummer);
   var gfx = obj.src;
   if (gfx.indexOf("ball.gif") > –1) {
      obj.src="kreuz.gif";
   } else {
      obj.removeNode(false);
   }
}

Galileo Computing

16.3.3 Zugriff auf Tags  downtop

Es gibt noch eine Alternative zum Knotenzugriff via ID: Sie können auch spezifisch auf Tags zugreifen. Die entsprechende Methode des document-Objekts heißt getElementsByTagName(). Beachten Sie den Plural (Elements), denn Sie erhalten auf jeden Fall ein Array zurück, auch wenn es nur ein entsprechendes Element auf der Seite gibt. Damit lässt sich im ursprünglichen, absichtlich fehlerhaften Beispiel etwa die ID für das <body>-Element einsparen:

<html>
<head>
<title>DOM-Demo</title>
<script type="text/javascript"><!--
function mausklick(Nummer){
   var basis = document.getElementsByTagName("body")[0];
   var obj = basis.childNodes[Nummer + 1];
   var gfx = obj.src;
   if (gfx.indexOf("ball.gif") > –1) {
      obj.src="kreuz.gif";
   } else {
      obj.removeNode(false);
   }
}
//--></script>
</head>
<body>
<h3 id="Ueberschrift">DOM-Demo</h3>
<img src="ball.gif" id="Ball1" onclick="mausklick(1);" />
<img src="ball.gif" id="Ball2" onclick="mausklick(2);" />
<img src="ball.gif" id="Ball3" onclick="mausklick(3);" />
<img src="ball.gif" id="Ball4" onclick="mausklick(4);" />
</body>
</html>

Galileo Computing

16.3.4 Beispiele  toptop

Zum Abschluss dieser DOM-Einführung noch zwei kleine Beispiele, die aufzeigen, wie Sie per DOM schnell Elemente der aktuellen Seite hinzufügen können – eine Technik, die in Kapitel 18 wichtig werden wird. Wir beginnen mit einer Aufzählungsliste:

<ul id="Liste"></ul>

Wie Sie sehen, ist die Liste leer. Die Daten für die Liste stehen in folgendem Objekt:

var daten = [
   {"text": "Mozilla", "url": "http://www.mozilla.com/"},
   {"text": "Microsoft", "url": "http://www.microsoft.com/"},
   {"text": "Opera", "url": "http://www.opera.com/"}
];

Unser Ziel ist es nun, diese Daten in die Liste einzufügen, und zwar als verlinkten Text. Werfen wir einen Blick auf das entsprechende Markup für ein Listenelement:

<li><a href="http://www.mozilla.com/">Mozilla</a></li>

Wir müssen also die folgenden DOM-Elemente erzeugen:

gp  Das <li>-Element
gp  Das <a>-Element samt dem Attribut href
gp  Den Textknoten mit dem Linktext

Am Ende müssen Sie diese Elemente untereinander einhängen: den Textknoten unterhalb des Links, den Link unterhalb des Listenelements, und natürlich abschließend das Listenelement unterhalb der Liste selbst.

Sie sehen: Das ist zu Anfang ein wenig ungewohnt und auch etwas aufwändig, geht aber nach wiederholtem Üben sehr leicht von der Hand. Hier ist das vollständige Listing:

<html>
<head>
<title>DOM-Demo</title>
<script type="text/javascript"><!--
var daten = [ {"text": "Mozilla", "url":
"http://www.mozilla.com/"}, {"text": "Microsoft", "url":
"http://www.microsoft.com/"}, {"text": "Opera", "url": "http://www.opera.com/"}
];

window.onload = function() {
   var liste = document.getElementById("Liste");
   for (var i = 0; i < daten.length; i++) {
      var link = daten[i];
      var li = document.createElement("li");
      var a = document.createElement("a");
      a.setAttribute("href", link.url);
      var txt = document.createTextNode(link.text);
      a.appendChild(txt);
      li.appendChild(a);
      liste.appendChild(li);
   }
}
//--></script>
</head>
<body>
<ul id="Liste"></ul>
</body>
</html>

Natürlich können Sie statt document.getElementById("Liste") im vorliegenden Beispiel auch document.getElementsByTagName("ul")[0] verwenden.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 16.6     Die dynamisch per DOM erzeugte Liste

Das zweite Beispiel soll etwas komplexer sein: Diesmal soll eine komplette Tabelle erzeugt und in den DOM-Baum eingehängt werden. Dabei gibt es eine wichtige Besonderheit: Unter bestimmten Umständen ist der Internet Explorer sehr wählerisch, was den (korrekten) Aufbau einer per DOM erzeugten Tabelle betrifft. Die Tabellenzellen müssen nämlich im <tbody>-Element platziert werden (und etwaige <th>-Zellen innerhalb von <thead>).

Von der Technologie her ist das nichts Neues: Sie erzeugen Elemente mit createElement() und hängen sie per appendChild() untereinander. Hier der Code für <thead>:

var table = document.createElement("table");
var thead = document.createElement("thead");
var tr = document.createElement("tr");
var th1 = document.createElement("th");
var th1text = document.createTextNode("Hersteller");
th1.appendChild(th1text);
var th2 = document.createElement("th");
var th2text = document.createTextNode("URL");
th2.appendChild(th2text);
tr.appendChild(th1);
tr.appendChild(th2);
thead.appendChild(tr);
table.appendChild(thead);

Auch der <tbody>-Abschnitt bietet wenig Neues, Sie müssen nur eine Menge Elemente erstellen. Eine kleine Besonderheit gibt es jedoch schon: Der Linktext und der Text in der linken Spalte sollen identisch sein. Sie können aber einen Knoten nicht an zwei Stellen in den DOM-Baum einhängen, denn Knoten werden wie Referenzen oder Zeiger gehandhabt, nicht wie Kopien. Das heißt, Sie müssen zunächst eine Knotenkopie erzeugen, was die Methode cloneNode() erledigt. Diese Methode erwartet als Parameter die Angabe, ob auch Unterknoten mit dupliziert werden sollen (true) oder nicht (false). Da der Textknoten selbst keine Unterknoten besitzt, genügt die Angabe false:

var tbody = document.createElement("tbody");
for (var i = 0; i < daten.length; i++) {
   var link = daten[i];
   var tr = document.createElement("tr");
   var td1 = document.createElement("td");
   var td1txt = document.createTextNode(link.text);
   td1.appendChild(td1txt);
   var td2 = document.createElement("td");
   var a = document.createElement("a");
   a.setAttribute("href", link.url);
   a.appendChild(td1txt.cloneNode(false));
   td2.appendChild(a);
   tr.appendChild(td1);
   tr.appendChild(td2);
   tbody.appendChild(tr);
}

Das war es auch schon fast, die Tabelle muss nur noch fertiggestellt und in das Dokument eingefügt werden:

table.appendChild(tbody);
var body = document.getElementsByTagName("body")[0];
body.appendChild(table);

Hier noch einmal der komplette Code im Überblick:

<html>
<head>
<title>DOM-Demo</title>
<script type="text/javascript"><!--
var daten = [ {"text": "Mozilla", "url":
"http://www.mozilla.com/"}, {"text": "Microsoft", "url":
"http://www.microsoft.com/"}, {"text": "Opera", "url": "http://www.opera.com/"}
];

window.onload = function() {
   var body = document.getElementsByTagName("body")[0];
   var table = document.createElement("table");

   var thead = document.createElement("thead");
   var tr = document.createElement("tr");
   var th1 = document.createElement("th");
   var th1text = document.createTextNode("Hersteller");
   th1.appendChild(th1text);
   var th2 = document.createElement("th");
   var th2text = document.createTextNode("URL");
   th2.appendChild(th2text);
   tr.appendChild(th1);
   tr.appendChild(th2);
   thead.appendChild(tr);
   table.appendChild(thead);

   var tbody = document.createElement("tbody");
   for (var i = 0; i < daten.length; i++) {
      var link = daten[i];
      var tr = document.createElement("tr");

      var td1 = document.createElement("td");
      var td1txt = document.createTextNode(link.text);
      td1.appendChild(td1txt);
      var td2 = document.createElement("td");
      var a = document.createElement("a");
      a.setAttribute("href", link.url);
      a.appendChild(td1txt.cloneNode(false));
      td2.appendChild(a);

      tr.appendChild(td1);
      tr.appendChild(td2);
      tbody.appendChild(tr);
   }
   table.appendChild(tbody);

   body.appendChild(table);
}
//--></script>
</head>
<body>
</body>
</html>

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 16.7     Die dynamisch per DOM erzeugte Tabelle

Sie sehen also: Das ist viel Tipparbeit, aber doch eigentlich gar nicht so schwierig.

Die JavaScript-Programmierung wird sich zweifelsohne mehr in Richtung DOM bewegen – das steht außer Frage. Da die Browser der Versionsnummer 4 ausgestorben sind (so kennen weder der Internet Explorer 4 noch der Netscape 4 die DOM-Methoden wie beispielsweise getElementById() oder document.getElementsByTagName()), kann man mittlerweile DOM mit gutem Gewissen einsetzen. Allerdings ist das Denken in Baumstrukturen nicht immer intuitiv; schöner ist es doch, mit dem bekannten JavaScript-Objekten wie etwa Image oder den Formularfeldern zu arbeiten. Der Trend geht jedoch langsam, aber sicher hin zu DOM. Warum? Weil Sie damit vor allem Text auf einer Seite verändern und neue HTML-Elemente hinzufügen können, wie weiter oben gezeigt wurde. Die folgenden Kapitel stehen ganz im Zeichen dieser Einsatzszenarios und zeigen DHTML und insbesondere AJAX: moderne Ansätze für die JavaScript-Programmierung, die der Sprache einen neuen Aufwind gegeben haben.

 

 <<   zurück
  
  Zum Katalog
Zum Katalog: JavaScript und AJAX
JavaScript und AJAX
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: JavaScript und AJAX - Das Video-Training






 JavaScript und AJAX -
 Das Video-Training


Zum Katalog: Webseiten programmieren und gestalten






 Webseiten
 programmieren
 und gestalten


Zum Katalog: XHTML, HTML und CSS






 XHTML, HTML und CSS


Zum Katalog: CSS-Praxis






 CSS-Praxis


Zum Katalog: AJAX






 AJAX


Zum Katalog: PHP 5 und MySQL 5






 PHP 5 und MySQL 5


Zum Katalog: TYPO3 4.0






 TYPO3 4.0


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de