Abschnitt 13 · Lektion 3
Was HTML schon prüft
Wer ein Alter von 12 einträgt, wo 18 verlangt ist, soll das erfahren, bevor das Formular abgeschickt ist. Für die häufigsten Regeln braucht es dafür kein JavaScript, das Markup kann sie selbst, und der Code fragt sie nur noch ab.
Die Regeln im Markup
<form id="formular">
<p><label for="name">Name</label> <input id="name" name="name" required value=""></p>
<p><label for="email">E-Mail</label> <input id="email" name="email" type="email" value="keine-adresse"></p>
<p><label for="alter">Alter</label> <input id="alter" name="alter" type="number" min="18" max="120" value="12"></p>
<p><label for="plz">PLZ</label> <input id="plz" name="plz" pattern="[0-9]{5}" value="123"></p>
<button type="submit">Absenden</button>
</form>
<pre id="protokoll"></pre> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
button,
input,
select,
textarea {
font: inherit;
}
button {
padding: 0.4rem 0.8rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
background: #fafaf9;
cursor: pointer;
}
input,
select,
textarea {
padding: 0.35rem 0.5rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
} const protokoll = document.getElementById("protokoll");
for (const feld of document.querySelectorAll("input")) {
// checkValidity fragt, ob das Feld nach den HTML-Regeln
// in Ordnung ist. validationMessage ist der Text, den der
// Browser dazu anzeigen würde, in der Sprache des Nutzers.
const zeile = [
feld.name,
feld.checkValidity() ? "gültig" : "ungültig",
feld.validationMessage || "keine Meldung",
].join(" | ");
protokoll.textContent = `${protokoll.textContent}${zeile}\n`;
}
// validity sagt sogar, WORAN es lag.
const alter = document.getElementById("alter");
console.log("zu klein?", alter.validity.rangeUnderflow);
console.log("leer?", document.getElementById("name").validity.valueMissing);
console.log("Muster verfehlt?", document.getElementById("plz").validity.patternMismatch);
// Und für das ganze Formular auf einmal.
console.log("Formular gültig?", document.getElementById("formular").checkValidity()); Fünf Attribute decken die meisten Formulare ab.
requiredverlangt, dass das Feld nicht leer bleibt.type="email"verlangt eine Adresse,type="number"eine Zahl.minundmaxbegrenzen eine Zahl,minlengthundmaxlengthdie Länge eines Textes.patternnimmt einen regulären Ausdruck aus Abschnitt 9.
Diese Regeln wirken ohne JavaScript, auf jedem Gerät, und ihre Meldungen kommen in der Sprache des Browsers, ohne dass jemand sie übersetzen muss. Der Typ tut nebenbei noch mehr, auf dem Telefon bringt type="email" eine Tastatur mit @ mit und type="number" eine mit Ziffern. Im ersten Beispiel sind alle vier Felder absichtlich falsch gefüllt. Ein Klick auf „Absenden“ schickt nichts ab, der Browser hält am ersten davon an und stellt seine eigene Blase daneben, ohne eine Zeile eigenen Code.
pattern und die Anker
<form id="formular">
<p><label for="plz">PLZ</label> <input id="plz" name="plz" pattern="[0-9]{5}"></p>
</form>
<pre id="protokoll"></pre> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
button,
input,
select,
textarea {
font: inherit;
}
button {
padding: 0.4rem 0.8rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
background: #fafaf9;
cursor: pointer;
}
input,
select,
textarea {
padding: 0.35rem 0.5rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
} const plz = document.getElementById("plz");
const protokoll = document.getElementById("protokoll");
// Dasselbe Muster wie in Abschnitt 9, nur ohne ^ und $.
// Der Browser prüft trotzdem den ganzen Text.
for (const wert of ["04103", "041030", "PLZ 04103", ""]) {
plz.value = wert;
const zeile = `"${wert}" ist ${plz.checkValidity() ? "gültig" : "ungültig"}`;
protokoll.textContent = `${protokoll.textContent}${zeile}\n`;
}
// Das leere Feld ist gültig, denn ohne required darf es leer
// bleiben. pattern prüft nur, was drinsteht.
console.log("required?", plz.required); Ein Muster in pattern gilt immer für den ganzen Inhalt des Feldes. Der Browser setzt ^ und $ selbst, und pattern="[0-9]{5}" lässt deshalb 04103 durch, 041030 und PLZ 04103 aber nicht. Mit eigenen Ankern geht es auch, nur ändert sich dadurch nichts.
Das leere Feld im zweiten Beispiel ist gültig. pattern prüft nur, was drinsteht, und ob überhaupt etwas drinstehen muss, sagt allein required.
Dieselben Regeln aus JavaScript
feld.checkValidity()lieferttrueoderfalse.feld.validationMessageist der Text, den der Browser anzeigen würde.feld.validitysagt, woran es lag,valueMissing,typeMismatch,rangeUnderflow,patternMismatchund einige mehr.formular.checkValidity()fragt für alle Felder auf einmal.
In der Eingabezeile der Console antwortet alter.validity.rangeUnderflow im ersten Beispiel mit true, die 12 liegt unter 18. Nach alter.value = "30" antwortet alter.checkValidity() mit true, denn die Regeln aus dem Markup prüfen den Wert, der jetzt im Feld steht. alter.validity als Ganzes antwortet nur mit ValidityState {}, aus demselben Grund wie beim Ereignis in Abschnitt 12.
novalidate und eigene Worte
<form id="formular" novalidate>
<p>
<label for="plz">PLZ</label>
<input id="plz" name="plz" required pattern="[0-9]{5}" value="123" aria-describedby="fehler-plz">
<span id="fehler-plz"></span>
</p>
<p>
<label for="anzahl">Anzahl</label>
<input id="anzahl" name="anzahl" type="number" min="1" max="10" value="12" aria-describedby="fehler-anzahl">
<span id="fehler-anzahl"></span>
</p>
<p><button type="submit">Absenden</button></p>
</form> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
button,
input,
select,
textarea {
font: inherit;
}
button {
padding: 0.4rem 0.8rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
background: #fafaf9;
cursor: pointer;
}
input,
select,
textarea {
padding: 0.35rem 0.5rem;
border: 1px solid #d6d3d1;
border-radius: 6px;
} const formular = document.getElementById("formular");
// Die Regeln bleiben im Markup. JavaScript fragt nur, welche
// verletzt ist, und sagt es in eigenen Worten.
function meldungFuer(feld) {
const gueltigkeit = feld.validity;
if (gueltigkeit.valueMissing) return "Das Feld ist leer";
if (gueltigkeit.patternMismatch) return "Eine Postleitzahl hat fünf Ziffern";
if (gueltigkeit.rangeOverflow) return `Höchstens ${feld.max}`;
return "";
}
formular.addEventListener("submit", (event) => {
// novalidate am Formular: der Browser hält nicht mehr an und
// zeigt keine Blase. Die Regeln gelten trotzdem weiter.
event.preventDefault();
for (const feld of formular.querySelectorAll("input")) {
document.getElementById(`fehler-${feld.id}`).textContent = meldungFuer(feld);
}
console.log("Formular gültig?", formular.checkValidity());
}); novalidate am Formular schaltet die Blasen ab. Die Regeln schaltet es nicht ab, checkValidity() und validity antworten weiter wie vorher, und ab hier ist der eigene Code für die Meldung zuständig.
Wer eigene Meldungen anzeigt, ergänzt die eingebaute Prüfung, statt sie wegzuwerfen. Die Attribute bleiben im Markup, denn sie beschreiben, was das Feld verlangt, und andere Werkzeuge lesen das aus. Das dritte Beispiel fragt validity nach dem Grund und schreibt ihn in eigenen Worten neben das Feld.
Für eine Adresse ist der Browser dabei großzügiger als das grobe Muster aus Abschnitt 9. ida@example gilt bei type="email" als gültig, auch ohne Punkt, denn auch eine Adresse in einem Firmennetz ohne Endung ist eine Adresse.
Was HTML nicht kennt, etwa ein Passwort, das mit einem zweiten übereinstimmen soll, braucht eine eigene Prüfung, und die kommt in der nächsten Lektion.
In der Aufgabe sagt eine Funktion für jedes Feld, welche Regel aus dem Markup verletzt ist, in eigenen Worten.
Zum Mitnehmen
required, type, min, max und pattern prüfen ein Feld ohne eine Zeile JavaScript, und pattern bringt seine Anker selbst mit. Aus dem Code fragt man dieselben Regeln über checkValidity und validity, und novalidate schaltet nur die Blasen des Browsers ab, nicht die Regeln.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.