19.3 Formulare und Event Handler
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.
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 sogenannte Event Handler (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.
19.3.1 Erstes Beispiel
Hier zunächst ein kleines Beispieldokument, das beides verwendet:
<html>
<head>
<title>Erster Formulartest</title>
</head>
<body>
<h1>Der Gruß-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="readonly" />
</form>
</body>
</html>
Dazu sind einige Erläuterungen erforderlich:
- 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.
- Das Ausgabefeld gruss besitzt die spezielle Eigenschaft »schreibgeschützt«, die durch das Attribut readonly="readonly" 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.
- 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.
- 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 Dokumentobjekts zugegriffen, und zwar auf dessen Eigenschaft value – es handelt sich um den Wert oder genauer den Inhalt des Textfelds. Auf dieselbe Weise erfolgt der Zugriff auf den Wert oder Inhalt des Textfelds user, das heißt auf die Benutzereingabe. Durch die Wertzuweisung wird der passende Gruß in das Ausgabefeld geschrieben.
19.3.2 Zugriff auf Formulare und ihre Elemente
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 zuvor) ein Name zugewiesen, 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 mithilfe von
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.
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 derjenigen 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>
Dann kann der Zugriff auf das Textfeld eingabe auf unterschiedliche Weise 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.
Kleiner Rechner mit einem Formular
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 diese dann über die Event Handler aufzurufen.
Im Folgenden wird ein kleiner formularbasierter Taschenrechner vorgestellt. Sie können zwei Zahlen eingeben und durch Anklicken der gewünschten Operation das Ergebnis ermitteln.
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.
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>
Formularauswertung
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? Haben bestimmte Felder Werte, die gewisse formale Kriterien erfüllen (zum Beispiel Postleitzahlen oder E-Mail-Adressen)? Die wichtigsten Möglichkeiten bieten die eingebauten String-Methoden sowie reguläre Ausdrücke. Beide werden im Folgenden vorgestellt.
Jeder String-Ausdruck kann in JavaScript als Objekt betrachtet werden, und eine Reihe von Methoden können zum Zugriff auf dieses Objekt angewandt werden:
- Die Eigenschaft String.length gibt die Länge eines Strings in Zeichen an. Beispiele:
"JavaScript".length // liefert 10
"".length // liefert 0 - 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"
- 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: Die Angabe 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!" - 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 0
"javascript".indexOf("nein") // liefert -1
"in den Rhein hinein".indexOf("ein") // liefert 9 - 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
Hier zwei Beispiele zur Untersuchung von Eingaben mit diesen Methoden:
- Untersuchung einer E-Mail-Adresse
Die Variable mail sei der Inhalt eines Texteingabefeldes. Der Inhalt soll daraufhin überprüft werden, ob es sich formal um eine E-Mail-Adresse handeln kann. Der folgende Codeblock führt entsprechende Tests durch:// 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!");
} - Untersuchung einer Postleitzahl
Die Variable plz soll daraufhin untersucht werden, ob sie eine gültige deutsche Postleitzahl enthält (fünf Stellen, nur Ziffern):// 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!");
}
Eine benutzerfreundliche Erweiterung kann übrigens darin bestehen, den Cursor bei der Formularüberprüfung automatisch in das Textfeld zu setzen, in dem der erste Fehler gefunden wurde. Schematisch funktioniert das folgendermaßen:
document.Formular.Element.focus();
Hier die konkrete Schreibweise für ein Feld namens kunde im Formular bestell:
document.bestell.kunde.focus();
Die Syntax für reguläre Ausdrücke in JavaScript wurde aus Perl übernommen (siehe Kapitel 10, »Konzepte der Programmierung«). Ihre Verwendung funktioniert allerdings anders.
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(/^\d{5}$/) {
alert ("Dies ist keine gueltige PLZ!");
}
Der reguläre Ausdruck /^\d{5}$/ trifft auf genau fünf beliebige Ziffern zu, beschreibt also eine deutsche Postleitzahl.
Auch der Test der E-Mail-Adresse beschränkt sich nun auf die folgende Kurzfassung:
if (!mail.match(/^[^\@]+\@[^\@]+$/)) {
alert ("E-Mail-Adresse ungueltig!");
}
Selbst für Namen ließe sich eine Art Plausibilitätskontrolle durchführen: Der Ausdruck /[^\s]+\s+[^\s]+/ verlangt mindestens zwei Blöcke von Zeichen (»Nicht-Leerzeichen«), die durch mindestens ein Whitespace-Element voneinander getrennt sind.
Für die Auswertung einer Namenseingabe mit der Bezeichnung kunde könnte folgender Code verwendet werden:
if (!kunde.match(/[^\s]+\s+[^\s]+/)) {
alert ("Bitte VOR- und NACHNAMEN angeben!");
}
Um die Verwendung regulärer Ausdrücke in JavaScript zu verdeutlichen, folgen noch einige praktische Beispiele.
In Webforen, 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" type="text/javascript">
window.location.href="http://meinewerbung.com";
</script>
Durch diesen Code erfolgt sofort ein Sprung zur angegebenen Seite (solche »automatischen Hyperlinks« werden im Abschnitt »Automatische Hyperlinks – History und Location« erläutert); das Forum/Gästebuch ist damit ausgeschaltet!
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:
/<[^>]+>/
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 und nicht bloß des ersten – funktioniert wie in Perl mithilfe 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, "");
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.
Es handelt sich um Eigenschaften des globalen Objekts RegExp, sie werden also als RegExp.$1 bis RegExp.$9 angesprochen. Sie können im Ersetzungs-String durch das übliche + verkettet werden. Leider stehen sie ausgerechnet in der Methode replace() nicht zur Verfügung; stattdessen müssen Sie ein RegExp-Objekt konstruieren und dessen Methode exec() ausführen. Hier ein kleines Beispiel:
In der Variablen kunde stehen Vor- und Nachname eines Kunden in der Form »Larry Wall«. Diese beiden Bestandteile sollen vertauscht und somit in »Wall, Larry« geändert 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.
Ihr Kommentar
Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.