Formularze - walidacja
Sprawdzanie danych, które wprowadza użytkownik to jedna z ważniejszych rzeczy, o jaką musimy zadbać, ale równocześnie też nie zawsze prosta do wykonania. Dane możemy sprawdzać na wiele sposobów, które często będzie uzależnione od budowy formularza i zawartych w nim mechanizmów.
Jak przeprowadzić walidację?
Przykładowa walidacja formularzy może przebiegać w kilku etapach:
- Pierwszy etap to dynamiczna podpowiedź w czasie wprowadzania danych przez użytkownika. Wykorzystamy tutaj zdarzenia change, focus, blur, keyup, keydown, keypress lub input - zależnie od sytuacji. Dodanie takich dynamicznych podpowiedzi znacząco może poprawić użyteczność naszego formularza, ale nie zawsze musimy je stosować
- Drugi etap to sprawdzenie danych w momencie, gdy użytkownik chce wysłać dany formularz. Jeżeli dane są poprawne, dany formularz wysyłamy. W przeciwnym razie pokazujemy stosowną informację.
- Ostatni - najważniejszy etap - to sprawdzenie przesłanych danych po stronie serwera. Jest to najważniejszy krok, ponieważ dane na nasz serwer mogą być wysłane na różne sposoby, nie tylko z naszego formularza.
Prosta walidacja
Domyślną akcją każdego formularza jest wysłanie danych na adres podany w atrybucie action
. Jeżeli atrybut ten nie zostanie podany, wtedy wysyłka danych jest wykonywana na aktualny adres.
<form action="https://kursjs.pl/login">
...
</form>
Wraz z wysłaniem formularza strona zostanie albo przeniesiona na nowy adres, albo zostanie przeładowana.
Aby zareagować na wysyłkę formularza pierwszą czynnością jest podpiąć się pod zdarzenie submit
formularza, a następnie użycie funkcji e.preventDefault()
, która przerwie domyślną akcję (wysyłkę):
const form = document.querySelector("form");
const input = form.querySelector("input");
form.addEventListener("submit", e => {
e.preventDefault();
//jeżeli wszystko ok to wysyłamy
if (input.value.length >= 3) {
form.submit();
} else {
//jeżeli nie to pokazujemy jakieś błędy
alert("Kolego wypełniłeś błędnie nasz super formularz");
}
})
Przy kilku polach można zbierać wyniki w tablicę. W poniższym kodzie zbieram tam teksty, które pojawią się w komunikacie błędu.
Równocześnie posługiwanie się okienkiem alert nie jest zalecanym rozwiązaniem. Okienko takie jest zbyt "inwazyjne" dla użytkownika, a poza tym nie mamy w ogóle możliwości zmiany jego wyglądu.
<form class="form" method="post" id="form">
<div class="form-row">
<label for="name">Imię (min. 3 znaki)*</label>
<input type="text" name="name" id="name">
</div>
<div class="form-row">
<label for="name">Email*</label>
<input type="email" name="email" id="email">
</div>
<div class="form-message"></div> <!-- tu trafią błędy -->
<div class="form-row">
<button type="submit" class="button submit-btn">
Wyślij
</button>
</div>
</form>
const form = document.querySelector("form");
const inputName = form.querySelector("input[name=name]");
const inputEmail = form.querySelector("input[name=email]");
const formMessage = form.querySelector(".form-message");
const regEmail = /\S+@\S+\.\S+/; //wzór do sprawdzania emaili
form.addEventListener("submit", e => {
e.preventDefault();
//tablica z błędami
let formErrors = [];
if (inputName.value.length <= 3) {
formErrors.push("Wypełnij poprawnie pole z imieniem");
}
//poprawność emaila sprawdzam za pomocą wyrażeń regularnych
if (!regEmail.test(inputEmail.value)) {
formErrors.push("Wypełnij poprawnie pole z emailem");
}
//jeżeli nie ma błędów wysyłamy formularz
if (!formErrors.length) {
form.submit();
//...lub dynamicznie wysyłamy dane za pomocą Ajax
//równocześnie reagując na odpowiedź z serwera
} else {
//jeżeli jednak są jakieś błędy...
formMessage.innerHTML = `
<h3 class="form-error-title">Przed wysłaniem proszę poprawić błędy:</h3>
<ul class="form-error-list">
${formErrors.map(el => `<li>${el}</li>`).join("")}
</ul>
`;
}
});
Powyższy kod moglibyśmy też rozbudować dodając dynamiczne reagowanie pól na stan wypełnienia za pomocą dodawania dodatkowej klasy is-invalid
w momencie, gdy pole jest błędnie wypełnione.
const inputName = form.querySelector("input[name=name]");
const inputEmail = form.querySelector("input[name=email]");
const formMessage = form.querySelector(".form-message");
const regEmail = /\S+@\S+\.\S+/;
//dynamiczne podpowiedzi na pól
inputName.addEventListener("input", () => {
inputName.classList.toggle("is-error", inputName.value.length <= 3);
});
inputEmail.addEventListener("input", () => {
inputEmail.classList.toggle("is-error", !regEmail.test(inputEmail.value));
});
form.addEventListener("submit", e => {
e.preventDefault();
let formErrors = [];
//usuwam domyślnie wszystkie zaznaczenia błędów
for (let el of [inputName, inputEmail]) {
el.classList.remove("is-invalid");
}
if (inputName.value.length <= 3) {
formErrors.push("Wypełnij poprawnie pole z imieniem");
inputName.classList.add("is-invalid");
}
if (!regEmail.test(inputEmail.value)) {
formErrors.push("Wypełnij poprawnie pole z emailem");
inputEmail.classList.add("is-invalid");
}
if (!formErrors.length) { //jeżeli nie ma błędów wysyłamy formularz
e.target.submit();
//...lub dynamicznie wysyłamy dane za pomocą Ajax
//równocześnie reagując na odpowiedź z serwera
} else {
//jeżeli jednak są jakieś błędy...
formMessage.innerHTML = `
<h3 class="form-error-title">Proszę poprawić błędy:</h3>
<ul class="form-error-list">
${formErrors.map(el => `<li>${el}</li>`).join("")}
</ul>
`;
}
});
W naszym kodzie testy powtarzają się w kilku miejscach. Warto tutaj dodać odpowiednie funkcje sprawdzające:
const inputName = form.querySelector("input[name=name]");
const inputEmail = form.querySelector("input[name=email]");
const formMessage = form.querySelector(".form-message");
function testFieldName() {
return inputName.value.length >= 3
}
function testFieldEmail() {
const regEmail = /\S+@\S+\.\S+/;
return regEmail.test(inputEmail.value);
}
//dynamiczne podpowiedzi na pól
inputName.addEventListener("input", () => {
inputName.classList.toggle("is-invalid", !testFieldName());
});
inputEmail.addEventListener("input", () => {
inputEmail.classList.toggle("is-invalid", !testFieldEmail());
});
form.addEventListener("submit", e => {
e.preventDefault();
let formErrors = [];
//usuwam domyślnie wszystkie zaznaczenia błędów
for (let field of [inputName, inputEmail]) {
field.classList.remove("is-invalid");
}
if (!testFieldName()) {
formErrors.push("Wypełnij poprawnie pole z imieniem");
inputName.classList.add("is-invalid");
}
if (!testFieldEmail()) {
formErrors.push("Wypełnij poprawnie pole z emailem");
inputEmail.classList.add("is-invalid");
}
if (!formErrors.length) {
form.submit();
} else {
formMessage.innerHTML = `
<h3 class="form-error-title">Proszę poprawić błędy:</h3>
<ul class="form-error-list">
${formErrors.map(el => `<li>${el}</li>`).join("")}
</ul>
`;
}
});