Tutorials › Teil 3: Die Seite
Kapitel 14 von 16
Formulare und Eingaben prüfen
Ein Formular, das nirgendwohin abgeschickt wird, sondern selbst rechnet. So arbeiten fast alle Werkzeuge in diesem Archiv.
<form id="bmi">
<label>Größe in cm <input name="groesse" type="number" value="178" required></label><br><br>
<label>Gewicht in kg <input name="gewicht" type="number" value="74" required></label><br><br>
<button>Berechnen</button>
</form>
<p id="ergebnis"></p>
<script>
const form = document.getElementById("bmi");
const ausgabe = document.getElementById("ergebnis");
form.addEventListener("submit", (e) => {
e.preventDefault();
const daten = new FormData(form);
const groesse = Number(daten.get("groesse")) / 100;
const gewicht = Number(daten.get("gewicht"));
const bmi = gewicht / (groesse * groesse);
ausgabe.textContent = "BMI: " + bmi.toFixed(1);
});
</script>
Zwei Dinge tragen das Ganze. Der Zuhörer hängt am <form>, nicht am Knopf. Und preventDefault verhindert, dass der Browser die Seite neu lädt.
Warum am Formular und nicht am Knopf
Weil ein Formular auf mehr als einen Weg abgeschickt wird. Ein Klick auf den Knopf. Die Eingabetaste in einem Textfeld. Bei manchen Hilfsmitteln auch anders.
Das submit-Ereignis fängt alle Wege ab. Ein click auf dem Knopf fängt nur einen.
An die Werte kommen
<form id="f">
<input name="text" value="Hallo">
<input name="zahl" type="number" value="42">
<input name="haken" type="checkbox" checked>
<select name="auswahl"><option value="a">A</option><option value="b" selected>B</option></select>
<button>Lesen</button>
</form>
<script>
const f = document.getElementById("f");
f.addEventListener("submit", (e) => {
e.preventDefault();
zeige("über elements:", f.elements.text.value);
zeige("Zahl als Typ:", typeof f.elements.zahl.value);
zeige("Haken:", f.elements.haken.checked);
zeige("Auswahl:", f.elements.auswahl.value);
const daten = Object.fromEntries(new FormData(f));
zeige("alles auf einmal:", daten);
});
</script>
Drei Wege, alle brauchbar.
form.elements.name greift direkt auf ein Feld zu. Kurz und lesbar.
new FormData(form) sammelt alles ein. Zusammen mit Object.fromEntries wird daraus ein Objekt, mit dem sich weiterarbeiten lässt.
Achte auf die zweite Zeile der Ausgabe. Auch bei type="number" ist der Wert eine Zeichenkette. Immer. Ohne Number() rechnest du mit Text weiter, und Kapitel 3 hat gezeigt, was dabei herauskommt.
Kästchen und Optionsfelder haben kein value, das dich interessiert, sondern checked.
Die eingebaute Prüfung
HTML kann selbst prüfen, ganz ohne JavaScript.
<form id="f">
<input name="mail" type="email" required placeholder="E-Mail" style="padding:5px">
<input name="plz" pattern="[0-9]{5}" required placeholder="PLZ" style="padding:5px;width:80px">
<button>Absenden</button>
</form>
<script>
document.getElementById("f").addEventListener("submit", (e) => {
e.preventDefault();
zeige("Alle Felder waren gültig.");
});
</script>
Lass ein Feld leer oder trag Unsinn ein. Der Browser blockiert das Abschicken und zeigt selbst eine Meldung an. Das submit-Ereignis feuert gar nicht erst.
Wichtige Attribute: required, type="email", type="url", min, max, minlength, maxlength, pattern für ein eigenes Muster.
Das kostet keine Zeile JavaScript und funktioniert auch, wenn ein Skript nicht lädt.
Eigene Meldungen
Die Standardmeldungen des Browsers sind allgemein gehalten. Präziser geht so:
<form id="f">
<input id="benutzer" required minlength="3" placeholder="Benutzername" style="padding:5px">
<button>Prüfen</button>
<p id="hinweis" style="color:#a3301c"></p>
</form>
<script>
const feld = document.getElementById("benutzer");
const hinweis = document.getElementById("hinweis");
document.getElementById("f").addEventListener("submit", (e) => {
e.preventDefault();
hinweis.textContent = "";
if (feld.validity.valueMissing) {
hinweis.textContent = "Bitte trag einen Namen ein.";
feld.focus();
return;
}
if (feld.validity.tooShort) {
hinweis.textContent = "Mindestens drei Zeichen, du hast " + feld.value.length + ".";
feld.focus();
return;
}
zeige("Angenommen:", feld.value.trim());
}, false);
document.getElementById("f").setAttribute("novalidate", "");
</script>
novalidate schaltet die Browsermeldungen ab, damit die eigenen greifen. feld.validity verrät trotzdem weiterhin, was genau nicht stimmt.
Ein guter Fehlertext sagt, was falsch ist und was zu tun ist. „Ungültige Eingabe" tut beides nicht.
Live mitrechnen
Statt auf den Knopf zu warten, kann man bei jeder Eingabe reagieren.
<label>Netto <input id="netto" type="number" value="100" style="padding:5px;width:100px"></label>
<p id="brutto"></p>
<script>
const netto = document.getElementById("netto");
const brutto = document.getElementById("brutto");
function rechnen() {
const wert = Number(netto.value);
if (Number.isNaN(wert) || netto.value.trim() === "") {
brutto.textContent = "Bitte eine Zahl eingeben.";
return;
}
brutto.textContent = (wert * 1.19).toLocaleString("de-DE", {
style: "currency", currency: "EUR",
}) + " brutto";
}
netto.addEventListener("input", rechnen);
rechnen();
</script>
Der Aufruf von rechnen() am Ende ist kein Versehen. Ohne ihn bliebe die Anzeige leer, bis jemand tippt, obwohl schon ein Wert im Feld steht.
Eingaben behalten
Was der Besucher eintippt, ist beim Neuladen weg. Mit localStorage muss es das nicht sein.
<textarea id="notiz" rows="4" style="width:90%;padding:6px"
placeholder="Tipp etwas und lad das Ergebnisfenster neu"></textarea>
<p><button id="leeren">Leeren</button></p>
<script>
const feld = document.getElementById("notiz");
try {
feld.value = localStorage.getItem("kurs-notiz") ?? "";
} catch (fehler) {
zeige("Speicher nicht verfügbar:", fehler.name);
}
feld.addEventListener("input", () => {
try { localStorage.setItem("kurs-notiz", feld.value); } catch (fehler) {}
});
document.getElementById("leeren").addEventListener("click", () => {
feld.value = "";
try { localStorage.removeItem("kurs-notiz"); } catch (fehler) {}
});
</script>
Vier Methoden reichen: setItem, getItem, removeItem, clear.
Gespeichert wird ausschließlich Text. Objekte müssen durch JSON.stringify und beim Lesen durch JSON.parse, siehe Kapitel 8.
Die try-Blöcke sind kein Übereifer. In einem privaten Fenster oder bei blockierten Website-Daten wirft schon der Zugriff auf localStorage eine Ausnahme, und dann steht das ganze Skript. Der Kasten oben läuft in einem abgeschotteten Rahmen, in dem der Speicher tatsächlich gesperrt ist.
Zwei Dinge noch dazu. localStorage bleibt, bis jemand es löscht. sessionStorage funktioniert genauso, wird aber beim Schließen des Tabs geleert. Und beides gilt nur pro Browser und Gerät, es ist kein Konto.
Im nächsten Kapitel wird gezeichnet.