Galileo Computing < openbook >
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.
Galileo Computing - Professionelle Buecher. Auch fuer Einsteiger.


Kompendium der Informationstechnik
 von Sascha Kersken
EDV-Grundlagen, Programmierung, Mediengestaltung
Buch: Kompendium der Informationstechnik
gp Kapitel 19 JavaScript
  gp 19.1 JavaScript-Einführung
  gp 19.2 JavaScript im HTML-Dokument
    gp 19.2.1 Erstes Beispiel: Ausgabe ins Dokument
  gp 19.3 Formulare und Event-Handler
    gp 19.3.1 Zugriff auf Formulare und ihre Elemente
    gp 19.3.2 Neufassung des Rechners mit einem Formular
    gp 19.3.3 Die Hintergrundfarbe dynamisch ändern
    gp 19.3.4 Formularauswertung
  gp 19.4 Datums- und Uhrzeit-Funktionen
    gp 19.4.1 Datums- und Uhrzeit-Methoden
    gp 19.4.2 Das Timeout – die JavaScript-»Stoppuhr«
    gp 19.4.3 Ein ausführliches Beispiel
  gp 19.5 Manipulation von Bildern
    gp 19.5.1 Erstes Beispiel: Austauschen eines Bildes auf Knopfdruck
    gp 19.5.2 Vorausladen von Bildern
    gp 19.5.3 Eine gut funktionierende Rollover-Lösung
    gp 19.5.4 Weitere Beispiele
  gp 19.6 Browser- und Fenster-Optionen
    gp 19.6.1 Browser-Eigenschaften
    gp 19.6.2 Automatische Hyperlinks – History und Location
  gp 19.7 DHTML und die Objektmodelle der Browser
    gp 19.7.1 W3C-DOM
    gp 19.7.2 Das klassische Internet-Explorer-Modell
    gp 19.7.3 Das klassische Netscape-Modell
    gp 19.7.4 Browserübergreifende Lösungen
  gp 19.8 Zusammenfassung

gp

Prüfungsfragen zu diesem Kapitel (extern)


Galileo Computing

19.3 Formulare und Event-Handler  downtop

Die Ein- und Ausgabe über prompt()-Boxen und das Schreiben in das Dokument sind zwar zum Erlernen von Operatoren und Ausdrücken hilfreich, entsprechen aber ansonsten nicht der üblichen Arbeit mit JavaScript. prompt()sollte nur für Test- und Debugging-Zwecke eingesetzt werden, genau wie seine beiden Kollegen alert()– nur Ausgabe in einer Box mit OK-Button – und confirm()– Ausgabe mit Auswahl zwischen OK- und Abbrechen-Button, die true beziehungsweise false zurückgeben.

Im »richtigen Leben« werden in der Regel HTML-Formulare zur Ein- und Ausgabe verwendet.

Event-Handler

Das einzige Problem besteht darin, dass Skripts aus Formularen heraus explizit aktiviert werden müssen: Die bisherigen Beispiele mit den prompt()-Boxen liefen automatisch beim Dokumentaufruf ab, ein Formular steht dagegen die ganze Zeit auf der Seite zur Verfügung, und Benutzer müssen entscheiden können, wann sie das entsprechende Skript aufrufen möchten. Dazu werden so genannte Event-Handler (deutsch etwa »Ereignisverarbeiter«) verwendet: Formal gesehen handelt es sich bei ihnen um HTML-Attribute, die jedoch den speziellen Zweck haben, JavaScript-Code auszuführen, der ihren Parameterwert bildet.

Listing 19.2 zeigt zunächst ein kleines Beispieldokument, das beides verwendet.

Listing 19.2   Ein einfaches Formular-Beispiel

<html>
  <head>
    <title>Erster Formulartest</title>
  </head>
  <body>
    <h1>Der Gru&szlig;-o-Mat</h1>
    <form name="formular">
      Dein  Name:
      <input type="text" name="user" size="40" />
      <input type="button" value="OK" 
      onclick="document.formular.gruss.value = 'Hallo ' 
      + document.formular.user.value + '!';" />
      <br />
      <input type="text" name="gruss" size="60" 
      readonly="true" />
    </form>
  </body>
</html>

Hier sind zunächst einige Erläuterungen erforderlich:

gp  Diejenigen Formularelemente, auf die JavaScript zugreift, erhalten bequemerweise jeweils einen Namen (das Attribut name). Das Formular selbst heißt formular; die beiden Textfelder heißen user für die Eingabe (bitte niemals name verwenden, da dieses Wort in JavaScript eine feste Bedeutung besitzt) und gruss für die Ausgabe.
gp  Das Ausgabefeld gruss besitzt die spezielle Eigenschaft »schreibgeschützt«, die durch das Attribut readonly="true" eingerichtet wird. Die klassische Schreibweise ist readonly ohne Parameterwert. Da das vorliegende HTML-Dokument jedoch in XHTML geschrieben ist, wird formal ein Wert für das Attribut benötigt.
gp  Der Button (das <input>-Tag mit dem Attribut type="button", also allgemeiner Button) besitzt einen Event-Handler. onclick="..." führt die als Wert übergebenen JavaScript-Anweisungen aus, sobald der Button angeklickt wird, in dem der Event-Handler steht. Formal gesehen ist onclick (und jeder andere Event-Handler) ein HTML-Attribut, deshalb gelten die entsprechenden Regeln: Zwischen onclick, dem Gleichheitszeichen und dem beginnenden Anführungszeichen darf kein Leerzeichen stehen. Innerhalb der Anführungszeichen des Attributwerts gilt dagegen die JavaScript-Syntax – mit einer Ausnahme: Es dürfen nur einfache Anführungszeichen (') verwendet werden! Ein doppeltes Anführungszeichen würde sonst vom Browser als Ende des HTML-Attributs erkannt. Auch \" funktioniert nicht, weil HTML diese Schreibweise nicht kennt.
gp  Die eigentliche JavaScript-Anweisung, also der Wert des Attributs onclick, ist folgende:
   document.formular.gruss.value = 
        'Hallo ' + document.formular.user.value + '!';
    Es wird auf das Unterobjekt gruss (das Textfeld) des Unterobjekts formular (das Formular) des Dokument-Objekts zugegriffen, und zwar auf dessen Eigenschaft value – es handelt sich um den Wert oder genauer den Inhalt des Textfelds. Auf dieselbe Weise wird auf den Wert oder Inhalt des Textfelds user, das heißt auf die Benutzereingabe, zugegriffen. Durch die Wertzuweisung wird der passende Gruß in das Ausgabefeld geschrieben.
       

Galileo Computing

19.3.1 Zugriff auf Formulare und ihre Elemente  downtop

Grundsätzlich befinden sich alle Formulare einer Seite, das heißt alle <form>...</form>-Bereiche, in einem Objekt-Array namens document.forms[]: Das erste Formular auf einer Seite ist document.forms[0], das zweite document.forms[1] und so weiter.

Wird einem Formular – wie im Beispiel oben – ein Name zugewiesen, dann erfolgt der Zugriff komfortabler: Das Formular kann entweder einfach als

document.Formularname

angesprochen werden – dazu muss der Formularname aber auf jeden Fall den formalen Regeln für JavaScript-Bezeichner entsprechen –, oder aber es wird mittels

document.forms["Formularname"]

der Name (statt der Nummer) als String-Index verwendet. Jedes JavaScript-Array kann – wie in PHP – numerisches Array und Hash in einem sein. Natürlich bleibt auch nach einer Namensvergabe der Zugriff über die Nummer möglich.

Formularelemente

Auf dieselbe Weise werden alle Elemente eines Formulars als document.Formular.elements[] in einem Array zusammengefasst. Elemente sind alle Textfelder, Textbereiche, Auswahlfelder, Radiobutton-Gruppen, Checkbox-Gruppen, Buttons und Hidden-Felder in der Reihenfolge, in der sie im HTML-Dokument definiert wurden.

Falls ein Element einen Namen besitzt (das Attribut name), kann dieser wieder als Objektbezeichner (document.Formular.Elementname) oder als Hash-Index (document.Formular.elements["Elementname"]) verwendet werden.

Nehmen Sie zum Beispiel an, das erste Formular in einem HTML-Dokument sähe folgendermaßen aus:

<form name="test">
  <input type="text" name="eingabe">
  <input type="button" value="OK">
</form>

Alle Zugriffsarten

Dann kann der Zugriff auf das Textfeld eingabe auf verschiedene Arten erfolgen:

document.forms[0].elements[0]
document.forms[0].elements["eingabe"]
document.forms[0].eingabe
 
document.forms["test"].elements[0]
document.forms["test"].elements["eingabe"]
document.forms["test"].eingabe
 
document.test.elements[0]
document.test.elements["eingabe"]
document.test.eingabe

Sie können also den numerischen Zugriff, die Objektnamen und die Hash-Indizes beliebig mischen.


Galileo Computing

19.3.2 Neufassung des Rechners mit einem Formular  downtop

Da es ziemlich wartungsunfreundlich und unübersichtlich wäre, größere Codemengen direkt in einen Event-Handler zu schreiben, ist es empfehlenswert, stattdessen in einem Skript im Head des Dokuments Funktionen zu definieren und sie dann über die Event-Handler aufzurufen.

Funktionen

Die Syntax für JavaScript-Funktionen ist mit der im vorigen Kapitel beschriebenen PHP-Funktionssyntax identisch: Auf das Schlüsselwort function folgt der Bezeichner der Funktion, anschließend steht in Klammern die (möglicherweise leere) Parameterliste. Den Rumpf der Funktion bildet schließlich ein Block, also ein Bereich in geschweiften Klammern. Das einzige Feature der PHP-Funktionen, das in JavaScript nicht funktioniert, ist der Call by Reference durch das &-Zeichen vor einem Parameter.

Für das Rechner-Beispiel wird zunächst in einem <script>-Block im Head die folgende Funktion definiert:

function rechnen (op)
{
   // Eingaben lesen
   var z1 = document.rechner.z1.value;
   var z2 = document.rechner.z2.value;
   // Sind es keine Zahlen?
   if (z1 != parseFloat (z1) || 
       z2 != parseFloat (z2)) {
      // Mindestens eine ist keine Zahl!
      document.rechner.erg.value = "Keine Zahl!";
      // Rücksprung aus der Funktion heraus
      return;
   }
   // Wenn wir HIER sind, waren es Zahlen!
   var erg;
   switch (op) {
      case "+":
         erg = parseFloat (z1) + parseFloat (z2);
         break;
      case "-":
         erg = z1 - z2;
         break;
      case "*":
         erg = z1 * z2;
         break;
      case "/":
         if (z2 == 0)
            erg = "0 VERBOTEN!";
         else
            erg = z1 / z2;
         break;
      default:
         erg = "KANN NICHT SEIN!";
   }
   document.rechner.erg.value = erg;
}

Das Formular mit den Eingabefeldern und den Buttons zum Aufrufen dieser Funktion im Body sieht dann so aus:

<form name="rechner">
  1. Zahl:
  <input type="text" name="z1" size="20" />
  2. Zahl:
  <input type="text" name="z2" size="20" />
  <br />
  <input type="button" value=" + "   onclick="rechnen ('+');" />
  <input type="button" value=" - "   onclick="rechnen ('-');" />
  <input type="button" value=" * "   onclick="rechnen ('*');" />
  <input type="button" value=" / "   onclick="rechnen ('/');" />
  <br />
  <input type="text" name="erg" size="40"   readonly="true" />
</form>

Galileo Computing

19.3.3 Die Hintergrundfarbe dynamisch ändern  downtop

Im folgenden größeren Beispielskript kann der Benutzer in drei Textfelder getrennt dezimale Werte zwischen 0 und 255 eingeben, die in Hexadezimalwerte umgerechnet und zur – automatisch angepassten – Hintergrundfarbe des Dokuments zusammengesetzt werden.

Farbumrechnung

Den Kern dieser Anwendung bildet die (selbst geschriebene) Funktion decToHex(), die einen Dezimalwert zwischen 0 und 255 entgegennimmt und den entsprechenden Hexadezimalwert zurückgibt. Diese Funktionsdefinition wird in einen Skript-Block im Head gesetzt und lautet folgendermaßen:

function decToHex(dec)
{
   var hexnums = new Array 
      ("0", "1", "2", "3", "4", "5", "6", "7", 
       "8", "9", "A", "B", "C", "D", "E", "F");
   var sechzehner = parseInt (dec / 16);
   var einer = dec % 16;
   var hex = hexnums[sechzehner] + hexnums[einer];
   return hex;
}

Als Erstes wird ein Array konstruiert, in dem die Liste der Hexadezimalziffern (0 bis F) so abgelegt ist, dass jeder Index dem jeweiligen Ziffernwert entspricht: hexnums[5] hat zum Beispiel den Wert "5"; hexnums[13] wäre dagegen "D".

Anschließend wird die »Sechzehnerstelle« ermittelt. Der dezimale Wert wird durch 16 geteilt; mittels parseInt() wird nur der ganzzahlige Anteil betrachtet. Ebenso wird durch die Modulo-Operation der Rest der Division als »Einerstelle« gespeichert. Beides sind Werte zwischen 0 und 15.

Schließlich werden diese beiden Werte als Indizes auf hexnums[] angewandt, um die korrekten Hexadezimalstellen zusammenzufügen. Mit Hilfe von return wird dieses Ergebnis zurückgegeben.

Im Übrigen funktioniert die Anwendung folgendermaßen:

In die drei Textfelder r, g und b des Formulars colorpicker werden die drei Farbwerte eingegeben. Ein Klick auf OK ruft die Funktion setColor() auf, in der die drei Einzelwerte in Hexadezimalwerte umgerechnet und als neue Hintergrundfarbe gesetzt werden. Zusätzlich wird diese neue Farbe in das schreibgeschützte Textfeld hexcolor geschrieben.

Die Funktion setColor() sieht folgendermaßen aus:

function setColor ()
{
   // Werte einlesen
   var r = document.colorpicker.r.value;
   var g = document.colorpicker.g.value;
   var b = document.colorpicker.b.value;
   // Werte überprüfen
   if (r < 0 || r > 255 || r != parseInt (r))  {
      alert ("Fehlerhafter Rot-Wert!");
      return;
   }
   if (g < 0 || g > 255 || g != parseInt (g))  {
      alert ("Fehlerhafter Gruen-Wert!");
      return;
   }
   if (b < 0 || b > 255 || b != parseInt (b))  {
      alert ("Fehlerhafter Blau-Wert!");
      return;
   }
   // HIER stehen auf jeden Fall korrekte Werte!
   var c = "#" + decToHex (r) 
         + decToHex (g) + decToHex (b);
   document.bgColor = c;
   document.colorpicker.hexcolor.value = c;
}
 

Im Body des Dokuments wird dann das folgende Formular definiert:

<form name="colorpicker">
  <table border="0" cellspacing="0" cellpadding="4">
    <tr>
      <td bgcolor="#FF0000">
        <font color="#FFFFFF">ROT:</font>
        <input type="text" name="r" size="10" />
      </td>
      <td bgcolor="#00FF00">
        <font color="#000000">GR&Uuml;N:</font>
        <input type="text" name="g" size="10" />
      </td>
      <td bgcolor="#0000FF">
        <font color="#FFFFFF">BLAU:</font>
        <input type="text" name="b" size="10" />
      </td>
      <td>
        <input type="button" value=" OK " 
        onclick="setColor ();" />
      </td>
    </tr>
    <tr>
      <td colspan="4" align="center" bgcolor="#FFFFFF">
        <font color="#000000">HEXADEZIMAL:</font>
        <input type="text" name="hexcolor" size="20" 
        readonly="true" />
      </td>
    </tr>
  </table>
</form>

Ergänzung zum Komfort-Farbwähler

Zusätzlich zu den bisher vorhandenen Elementen sollen zwei Radiobuttons hinzugefügt werden, die dem Benutzer die Wahl zwischen dem Einstellen der Hintergrundfarbe und der allgemeinen Textfarbe – document.fgColor – lassen.

Radiobuttons ansprechen

Radiobuttons werden so angesprochen: Die Radiobutton-Gruppe wird als Array der einzelnen Radiobuttons angesprochen (bei Checkboxen ist es genauso). Sie können auf die einzelnen Radiobuttons einer Gruppe mittels

document.Formular.Radiobuttongruppe[Button-Nr.]

zugreifen, wobei Button-Nr. bei 0 beginnt und die Buttons in der Reihenfolge im HTML-Dokument anspricht.

Die Eigenschaft checked ist für den einzelnen Button true, wenn er ausgewählt beziehungsweise angekreuzt ist, ansonsten false.

Im Body des Farbwählers müssen Sie über der Tabellenzeile mit dem Hexadezimalwert die folgende Ergänzung vornehmen:

<tr>
  <td colspan="4" bgcolor="#FFFFFF">
    <font color="#000000">
    <input type="radio" name="colortype" value="bg" />
    Hintergrundfarbe
    <input type="radio" name="colortype" value="fg" />
    Textfarbe
  </td>
</tr>

Ergänzen Sie anschließend in der Funktion setColor() die Anweisung

document.bgColor = c;

folgendermaßen:

if (document.colorpicker.colortype[0].checked)
   document.bgColor = c;
else if (document.colorpicker.colortype[1].checked)
   document.fgColor = c;
else
   alert ("Sie haben nicht den Bereich ausgewaehlt!");

Damit überhaupt Text in der allgemeinen Textfarbe existiert, können Sie Folgendes über die gesamte Tabelle setzen:

<h1>Der Farbw&auml;hler</h1>
<h2>W&auml;hl deine Farbe!</h2>

Das <body>-Tag sollte daraufhin so ergänzt werden:

<body bgcolor="#000000" text="#FFFFFF">

Galileo Computing

19.3.4 Formularauswertung  toptop

Es ist eine praktische Angelegenheit, HTML-Formulare schon vor dem Absenden direkt im Browser per JavaScript ein wenig auf Plausibilität zu überprüfen: Sind alle Pflichtfelder ausgefüllt worden? Haben bestimmte Felder Werte, die gewisse formale Kriterien erfüllen (zum Beispiel Postleitzahlen oder E-Mail-Adressen)?

Das Beispiel für alle Formularauswertungen ist das Formular in Abbildung 19.1. Der zugehörige HTML-Code steht in Listing 19.3.


Abbildung 19.1   Ein Beispielformular für die JavaScript-Auswertung

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


Listing 19.3   Ein Formular für verschiedene Überprüfungsbeispiele

<form name="bestell" action="/cgi-bin/order.pl" method="post">
  <table border="0" cellpadding="5">
    <tr>
      <td colspan="4" align="center">
        <h2>JAVASCRIPT MERCHANDISING GmbH</h2>
        Ich bestelle die folgenden Artikel:
      </td>
    </tr>
    <tr>
      <td colspan="3">
        <input type="checkbox" name="order" 
        value="tasse" />
        JavaScript-Tasse
      </td>
      <td align="right">8,99 &euro;</td>
    </tr>
    <tr>
      <td colspan="3">
        <input type="checkbox" name="order" 
        value="muetze" />
        JavaScript-M&uuml;tze
      </td>
      <td align="right">11,99 &euro;</td>
    </tr>
    <tr>
      <td colspan="3">
        <input type="checkbox" name="order" 
        value="shirt" />
        JavaScript-Tasse
      </td>
      <td align="right">14,99 &euro;</td>
    </tr>
    <tr>
      <td colspan="3">
        <input type="checkbox" name="order" 
        value="seife" />
        JavaScript-Seife
      </td>
      <td align="right">3,99 &euro;</td>
    </tr>
    <tr>
      <td colspan="4">zzgl. Porto/Verpackung (2,45 
      &euro;) bei Bestellungen unter 15,-- &euro;</td>
    </tr>
    <tr>
      <td>Name:</td>
      <td colspan="3">
        <input type="text" name="kunde" size="50" />
      </td>
    </tr>
    <tr>
      <td>E-Mail:</td>
      <td colspan="3">
        <input type="text" name="mail" size="50" />
      </td>
    </tr>
    <tr>
      <td>Stra&szlig;e:</td>
      <td colspan="3">
        <input type="text" name="str" size="50" />
      </td>
    </tr>
    <tr>
      <td>PLZ:</td>
      <td>
        <input type="text" name="plz" size="8" 
        maxlength="5" />
      </td>
      <td>Ort:</td>
      <td>
        <input type="text" name="ort" size="30">
      </td>
    </tr>
    <tr>
      <td>Telefon:</td>
      <td colspan="3">
        <input type="text" name="tel" size="50" />
      </td>
    </tr>
    <tr>
      <td>Lieferung:</td>
      <td>
        <input type="radio" name="liefer" 
        value="post" />
        Post
      </td>
      <td>
        <input type="radio" name="liefer" 
        value="ups" />
        UPS
      </td>
      <td>
        <input type="radio" name="liefer" 
        value="egal" />
        egal
      </td>
    </tr>
    <tr>
      <td>Zahlung:</td>
      <td colspan="2">
        <input type="radio" name="zahl" 
        value="rechn" />
        Rechnung
      </td>
      <td>
        <input type="radio" name="zahl" 
        value="scheck" />
        Scheck
      </td>
    </tr>
    <tr>
      <td>&nbsp;</td>
      <td colspan="2">
        <input type="radio" name="zahl" 
        value="ueber" />
        &Uuml;berweisung
      </td>
      <td>
        <input type="radio" name="zahl" 
        value="kredit" />
        Kreditkarte
      </td>
    </tr>
    <tr>
      <td colspan="2" align="center">
        <input type="button" value="Abschicken" 
        onclick="testForm ();" />
      </td>
      <td colspan="2" align="center">
        <input type="reset" value="Verwerfen" />
      </td>
    </tr>
  </table>
</form>

Button-Elemente

Beachten Sie, dass der Abschicken-Button nicht als Submit-Button, sondern als »normaler« Button realisiert wurde, weil das Formular nicht automatisch abgeschickt werden soll. Es soll zuerst per JavaScript überprüft werden, und nur, wenn alles in Ordnung ist, wird der Versand durchgeführt – ebenfalls per JavaScript.

Nichtsdestotrotz besitzt dieses Formular die Attribute action und method, weil diese auch beim JavaScript-Formularversand benötigt werden.

In einem ersten Schritt soll nur überprüft werden, ob alle Felder, die Pflichtangaben enthalten, überhaupt ausgefüllt wurden – der Einfachheit halber sind in diesem Formular alle Felder Pflichtfelder.

Im Head des Dokuments steht zu diesem Zweck das Skript aus Listing 19.4.

Listing 19.4   Überprüfung, ob ein Formular vollständig ausgefüllt ist

function testForm ()
{
   // Wurde etwas gekauft?
   // Annahme: Es wurde NICHTS gekauft:
   var gekauft = false;
   // Die Käufe schrittweise durchgehen
   var summe = 0;
   var preise = 
        new Array (8.99, 11.99, 14.99, 3.99);
   for (i = 0; i < 4; i++) {
      // Wurde Artikel Nr. i gekauft?
      if (document.bestell.order[i].checked) {
         // Aha! Es wurde etwas gekauft!
         gekauft = true;
         summe += preise[i];
      }
   }
   // Es wurde nichts gekauft!
   if (!gekauft) {
      alert ("Sie haben nichts gekauft!");
      return;
   }
   // Name eingegeben?
   var kunde = document.bestell.kunde.value;
   if (!kunde) {
      alert ("Kein Name eingegeben!");
      return;
   }
   var mail = document.bestell.mail.value;
   if (!mail) {
      alert ("Keine E-Mail-Adresse eingegeben!");
      return;
   }
   var str = document.bestell.str.value;
   if (!str) {
      alert ("Strasse vergessen!");
      return;
   }
   var plz = document.bestell.plz.value;
   if (!plz) {
      alert ("Postleitzahl vergessen!");
      return;
   }
   var ort = document.bestell.ort.value;
   if (!ort) {
      alert ("Der Ort fehlt!");
      return;
   }
   var tel = document.bestell.tel.value;
   if (!tel) {
      alert ("Keine Telefonnummer angegeben!");
      return;
   }
   // Liefermethode angegeben?
   var lmethode;
   if (document.bestell.liefer[0].checked)
      lmethode = "post";
   else if (document.bestell.liefer[1].checked)
      lmethode = "ups";
   else if (document.bestell.liefer[2].checked)
      lmethode = "egal";
   else {
      alert ("Keine Liefermethode gewaehlt!");
      return;
   }
   // Zahlungsweise angegeben?
   var zmethode;
   if (document.bestell.zahl[0].checked)
      zmethode = "rechn";
   else if (document.bestell.zahl[1].checked)
      zmethode = "scheck";
   else if (document.bestell.zahl[2].checked)
      zmethode = "ueber";
   else if (document.bestell.zahl[3].checked)
      zmethode = "kredit";
   else {
      alert ("Keine Zahlungsmethode angegeben!");
      return;
   }
   // Es wurde alles eingegeben!
   // Das Formular tatsächlich abschicken:
   document.bestell.submit ();
   // Gesamtpreis < 15 EUR?
   if (summe < 15)
      summe += 2.45;  // Porto & Verpackung
   alert ("Danke fuer Ihren Einkauf\n
      Summe: " + summe);
}

Im nächsten Schritt erfolgen einige Plausibilitätsprüfungen, das heißt Tests, in denen bestimmte Werte daraufhin überprüft werden, ob sie möglich oder unmöglich sind.

String-Methoden

Sehr nützlich sind dafür beispielsweise die String-Eigenschaften und -Methoden. Jeder String-Ausdruck kann in JavaScript als Objekt betrachtet werden, und eine Reihe von Methoden können zum Zugriff auf dieses Objekt angewandt werden:

gp  String.length (Eigenschaft) gibt die Länge eines Strings in Zeichen an. Beispiele:
"Bill Gates".length  // liefert 1 
"".length            // liefert 0
gp  String.charAt (Pos) liefert das Zeichen eines Strings an der Position Nummer Pos. Die erste Position ist 0, die letzte ist String.length - 1. Beispiel:
   "JavaScript".charAt (4)  // liefert "S"
gp  String.substring (Anf_Pos, End_Pos) gibt den Teilstring eines Strings an, beginnend mit dem Zeichen an der Position Anf_Pos (ab 0) bis vor das Zeichen End_Pos: End_Pos gibt das erste Zeichen an, das nicht mehr vorkommen soll (»bis ausschließlich ...«). Beispiele:
"JavaScript macht Spass".substring (11, 16)
   // liefert "macht"
"Java aber noch mehr!".substring (0, 5)
   // liefert "Java"
var text = "Hallo liebe Welt!";
text.substring (text.length - 4, text.length)
   // liefert "Welt!"
gp  String.indexOf (Teilstring) gibt die erste Position (ab 0) an, an der Teilstring in einem String beginnt, oder -1, wenn Teilstring gar nicht im String vorkommt. Beispiele:
"javascript".indexOf ("ja") 
          // liefert  "in den Rhein hinein"
.indexOf ("ein") // liefert 9
gp  String.lastIndexOf (Teilstring) gibt die letzte Position (ab 0) an, an der Teilstring im String beginnt, oder -1, wenn Teilstring nicht im String vorkommt. Beispiele:
"in den Rhein hinein".lastIndexOf ("in")  // 17
"javascript".lastIndexOf ("no") 
          // -1

Mit Hilfe dieser Methoden sollen die folgenden Felder untersucht werden:

gp  E-Mail: Es muss genau ein @-Zeichen vorkommen, dieses darf weder ganz am Anfang noch ganz am Ende der Adresse stehen.
gp  Postleitzahl: Eine deutsche Postleitzahl darf nur Ziffern enthalten und muss fünfstellig sein.

Alle übrigen Felder werden weiter unten mit Hilfe eines anderen Verfahrens untersucht.

1. Untersuchung der E-Mail-Adresse
       
    Der Abschnitt
       
var mail = document.bestell.mail.value;
if (!mail) {
   alert ("Keine E-Mail-Adresse!");
   return;
}
    wird durch die folgende Formulierung ersetzt:
       
var mail = document.bestell.mail.value;
// Annahme: E-Mail ist gültig:
var mailOK = true;
// E-Mail-Adresse vorhanden?
if (!mail)
   mailOK = false;
// "@"-Zeichen überhaupt vorhanden?
if (mail.indexOf ("@") == -1)
   mailOK = false;
// "@"-Zeichen am ANFANG oder am ENDE?
if (mail.indexOf ("@") == 0 || 
      mail.lastIndexOf ("@") == mail.length - 1)
   mailOK = false;
// MEHR als ein "@"-Zeichen?
if (mail.indexOf ("@") != mail.lastIndexOf ("@"))
   mailOK = false;
if (!mailOK) {
   alert ("E-Mail-Adresse ungültig!");
   return;
}
2. Untersuchung der Postleitzahl
       
    Der Abschnitt
       
var plz = document.bestell.plz.value;
if (!plz) {
   alert ("Postleitzahl vergessen!");
   return;
}
    wird ersetzt durch:
       
var plz = document.bestell.plz.value;
// Annahme: PLZ gültig!
var plzOK = true;
// PLZ zu lang oder zu kurz?
if (plz.length != 5) {
   plzOK = false;
} else {
   for (i = 0; i < 5; i++) {
      if (plz.charAt (i) < "0" || 
            plz.charAt (i) > "9")
         plzOK = false;
   }
}
if (!plzOK) {
   alert ("Postleitzahl inakzeptabel!");
   return;
}

Den Eingabefokus setzen

Eine benutzerfreundliche Erweiterung kann darin bestehen, den Cursor vor dem Rücksprung automatisch in das Textfeld zu setzen, in dem der erste Fehler gefunden wurde.

Schematisch funktioniert das folgendermaßen:

document.Formular.Element.focus();

Daher wird beispielsweise die Namensüberprüfung

var kunde = document.bestell.kunde.value;
if (!kunde) {
   alert ("Kein Name eingegeben!");
   return;
}

zu folgender Formulierung ergänzt:

var kunde = document.bestell.kunde.value;
if (!kunde) {
   alert ("Kein Name eingegeben!");
   document.bestell.kunde.focus();
   return;
}

Reguläre Ausdrücke

Im letzten Schritt werden einige Felder durch die Verwendung von regulären Ausdrücken (regular expressions) genauer untersucht. In JavaScript wurde die Syntax der regulären Ausdrücke selbst exakt aus Perl übernommen (siehe Kapitel 6, Konzepte der Programmierung), lediglich die Syntax ihrer Verwendung ist anders.

RegExp-Konstrukte

Wie in Perl stehen RegExp-Konstrukte auch in JavaScript nicht in Anführungszeichen, sondern zwischen zwei /-Zeichen:

/RegExp/

Als Erstes sehen Sie hier die einfachste JavaScript-Form für den Einsatz regulärer Ausdrücke: Die Methode

String.match (/RegExp/)

gibt true zurück, wenn der String dem Muster RegExp entspricht, ansonsten false.

Auf diese Weise lässt sich zum Beispiel die Postleitzahl viel schneller und einfacher überprüfen:

var plz = document.bestell.plz.value;
if (!plz.match (/^[0-9][0-9][0-9][0-9][0-9]$/)  {
   alert ("Dies ist keine gueltige PLZ!");
   return;
}

Der reguläre Ausdruck /^[0-9][0-9][0-9][0-9][0-9]$/ trifft auf genau fünf beliebige Ziffern zu, beschreibt also eine deutsche Postleitzahl. Diese Formulierung lässt sich durch /^[0-9]{5}$/ noch vereinfachen – eine Zahl in geschweiften Klammern gibt eine genaue Anzahl für den davor stehenden Ausdruck an. Zwei Zahlen in geschweiften Klammern, durch Komma getrennt, geben im Übrigen die Mindest- und die Höchstanzahl an.

Auch der Test der E-Mail-Adresse beschränkt sich nun auf die folgende Kurzfassung:

var mail = document.bestell.mail.value;
if (!mail.match (/[^\@]+\@[^\@]+/)) {
   alert ("E-Mail-Adresse ungueltig!");
   return;
}

Der komplexe Teilausdruck [^\@]+\@[^\@]+ besteht aus den folgenden Komponenten:

gp  [^\@]– beschreibt jedes beliebige Zeichen außer @.
gp  + – besagt, dass der vorige Ausdruck mindestens einmal vorkommen muss.
gp  \@ – es folgt genau ein @.
gp  [^\@]+ – wieder folgt mindestens ein beliebiges Zeichen außer @.

RegExp-Escape-Sequenzen

Das @-Zeichen als solches hat eine besondere Bedeutung, deshalb muss ein \ vorangestellt werden – genau wie bei allen anderen Zeichen, die in regulären Ausdrücken eine besondere Bedeutung haben, etwa. /, \, [, ], (, ), {, }, ., +, * oder ?.

Schließlich könnte auch noch eine kleine Plausibilitätskontrolle für Namen eingeführt werden: Der Ausdruck /[^\s]+\s+[^\s]+/ verlangt zwei Blöcke von Zeichen (»Nicht-Leerzeichen«), die durch mindestens ein Whitespace-Element voneinander getrennt sind.

Für die Auswertung des Namensfelds könnte folgender Code verwendet werden:

if (!kunde.match (/[^\s]+\s+[^\s]+/)) {
   alert ("Bitte VOR- und NACHNAMEN angeben!");
   document.bestell.kunde.focus();
   return;
}

Fortgeschrittene RegExp-Beispiele

Um die Verwendung regulärer Ausdrücke in JavaScript zu verdeutlichen, folgen hier noch einige Beispiele:

In Web-Foren, Gästebüchern oder ähnlichen Anwendungen besteht theoretisch die Möglichkeit, HTML-Code einzugeben und damit den Browsern der anderen Benutzer unterzuschieben. Im Extremfall schreibt jemand so etwas wie:

<script language="JavaScript">
window.location.href="http://meinewerbung.com";
</script>

Durch diesen Code erfolgt sofort ein Sprung zur angegebenen Seite (eine Art »automatischer Hyperlink«); das Forum/Gästebuch ist damit ausgeschaltet!

HTML-Tags entfernen

Insofern ist es für solche Anwendungen wünschenswert, gar keine HTML-Tags zuzulassen oder sie zumindest auf harmlose Textformatierungs-Tags zu beschränken.

Finden lassen sich HTML-Tags in Strings relativ leicht durch den folgenden Ausdruck:

/<[^>]+>/   // alles, was zwischen <...> steht

Das Problem ist, dass in einer Zeile mehrere HTML-Tags vorkommen können – dieser Ausdruck findet nur das erste von ihnen. Darüber hinaus genügt das Finden allein noch nicht, um den schädlichen Code durch harmlosen zu ersetzen.

Für Letzteres wird statt der Methode String.match() die Methode String.replace() verwendet, die einen regulären Ausdruck findet und an dessen Stelle einen beliebigen String setzt. Beispielsweise ersetzt

eingabe = eingabe.replace (/<[^>]+>/, "");

den ersten <>-Ausdruck im String eingabe durch gar nichts.

Das zweite Problem – das Finden und Ersetzen aller derartigen Ausdrücke im String – funktioniert wie in Perl mit Hilfe des Modifizierers /g (für »global«). Die korrekte Form der Anweisung lautet also allgemein so:

String.replace (/RegExp1/g, String2);

Im HTML-Tag-Beispiel müssen Sie also Folgendes schreiben:

eingabe = eingabe.replace (/<[^>]*>/g, "");

Sonderzeichen ersetzen

Ein anderes interessantes Beispiel bietet die folgende Funktion convert(), die »normale« Umlaute und einige andere wichtige Sonderzeichen durch die passenden HTML-Entity-Referenzen ersetzt:

function convert ()
{
   var ein = document.beitrag.eingabe.value;
   // Windows (iso-latin-1) Umlaute:
   ein = ein.replace (/ä/g, "&auml;");
   ein = ein.replace (/ö/g, "&ouml;");
   ein = ein.replace (/ü/g, "&uuml;");
   ein = ein.replace (/Ä/g, "&Auml;");
   ein = ein.replace (/Ö/g, "&Ouml;");
   ein = ein.replace (/Ü/g, "&Uuml;");
   ein = ein.replace (/ß/g, "&szlig;");
   // Mac-Umlaute:
   ein = ein.replace (/Š/g, "&auml;");
   ein = ein.replace (/š/g, "&ouml;");
   ein = ein.replace (/Ÿ/g, "&uuml;");
   ein = ein.replace (/_/g, "&Auml;");
   ein = ein.replace (/…/g, "&Ouml;");
   ein = ein.replace (/†/g, "&Uuml;");
   ein = ein.replace (/§/g, "&szlig;"); 
     // Sonstige Sonderzeichen:
   ein = ein.replace (/</g, "&lt;");
   ein = ein.replace (/>/g, "&gt;");
   ein = ein.replace (/"/g, "&quot;");
   document.beitrag.eingabe.value = ein;
}

Diese Lösung berücksichtigt bereits das Problem, dass Umlaute im Mac-Zeichensatz an anderer Stelle stehen als im Windows-Zeichensatz (iso-latin-1). Die entsprechenden Mac-Sonderzeichen habe ich mit Hilfe des kleinen Textkonverterprogramms AscOnA erzeugt, das unter www.medienwerkstatt-online.de/products/ascona/ascona.html zum Download bereitsteht. (Wenn Sie das Skript auf einem Mac öffnen, sehen natürlich die Umlaute im zweiten Teil korrekt aus, während im ersten Teil seltsame Sonderzeichen angezeigt werden.)

Treffer-Variablen

Wie in Perl können bestimmte Teile der durch reguläre Ausdrücke gefundenen Treffer im Ersetzungs-String verwendet werden: Jeder Teil eines regulären Ausdrucks, der in runde Klammern gesetzt wird, wird bei einem Treffer in einer automatischen Eigenschaft namens $1 bis $9 abgelegt – es sind mit anderen Worten neun Speicherplätze möglich.

Diese Eigenschaften sind solche des globalen Objekts RegExp, können also als RegExp.$1 bis RegExp.$9 angesprochen werden. Sie können im Ersetzungs-String durch das übliche + verkettet werden. Leider stehen sie ausgerechnet in der Methode replace() nicht zur Verfügung.

Hier ein kleines Beispiel:

In der Variablen kunde stehen Vor- und Nachname eines Kunden in der Form Larry Wall. Diese beiden Bestandteile sollen in Wall, Larry vertauscht werden. Dies funktioniert folgendermaßen:

var muster = /([^\s]+)\s+([^\s]+)/;
muster.exec (kunde);
kunde = RegExp.$2 + ", " + RegExp.$1;

([^\s]+) beschreibt ein oder mehrere Nicht-Leerzeichen, die durch die runden Klammern in RegExp.$1 gespeichert werden. \s+ steht für beliebig viel Whitespace; darauf folgt der zweite Klammerausdruck ([^\s]+), der wiederum ein oder mehrere Nicht-Leerzeichen beschreibt und in RegExp.$2 abgelegt wird.

Zuerst wird das RegExp-Objekt muster erstellt. Anschließend wird die Methode exec() des RegExp-Objekts muster mit dem zu durchsuchenden Text (hier: kunde) als Argument aufgerufen – die Reihenfolge ist also andersherum als bei match() und replace().

Der eigentliche Sinn von exec() besteht eben darin, aus einem regulären Ausdruck mit ()-Bereichen die Elemente $1 bis $9 zu extrahieren. Nun stehen die gewünschten Werte RegExp.$1 und RegExp.$2 zur Verfügung und können zur Bildung eines neuen Strings verwendet werden.

  

Einstieg in PHP 5

Einstieg in Java

C von A bis Z

Einstieg in C++

Einstieg in Linux

Einstieg in XML

Apache 2




Copyright © Galileo Press GmbH 2004
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 GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de