Пошук уроків, статей та іншого контенту
Реалізуєте перевірку полів, обробку submit і скасування стандартної поведінки форми.
Форма (<form>) збирає введені користувачем дані та за замовчуванням надсилає їх на адресу, вказану в атрибуті action.
<form action="/register" method="post">
<label>
Ім’я
<input name="name" type="text">
</label>
<button type="submit">Зареєструватися</button>
</form>Атрибут method визначає HTTP-метод:
get — дані додаються до URL як параметри запиту;
post — дані надсилаються в тілі запиту.
Під час натискання кнопки submit браузер запускає стандартний процес:
перевіряє вбудовані обмеження полів;
генерує подію submit для форми;
якщо обробку не скасовано, надсилає форму;
зазвичай перезавантажує сторінку або переходить на іншу адресу.
У сучасних застосунках часто потрібно обробити дані JavaScript-кодом без перезавантаження сторінки. Для цього використовується event.preventDefault().
submitОбробник потрібно додавати саме до форми, а не лише до кнопки:
const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
event.preventDefault();
console.log("Форму оброблено JavaScript-кодом");
});Це важливо, тому що форму можна надіслати не тільки кліком по кнопці:
клавішею Enter у текстовому полі;
викликом методу requestSubmit();
іншими елементами інтерфейсу.
Обробник submit охоплює всі ці способи.
HTML має стандартні атрибути для базової валідації:
<form>
<input name="username" required minlength="3">
<input name="email" type="email" required>
<input name="age" type="number" min="18" max="120">
<button type="submit">Надіслати</button>
</form>Основні атрибути:
required — поле не може бути порожнім;
type="email" — значення має відповідати формату електронної пошти;
minlength і maxlength — обмеження довжини тексту;
min і max — діапазон для числових значень;
pattern — регулярний вираз для перевірки тексту.
Якщо поле не проходить перевірку, браузер зазвичай не запускає подію submit, а показує власне повідомлення.
Вбудованих правил не завжди достатньо. Наприклад, можна перевірити, чи збігаються два паролі, або показати помилки в окремому блоці.
Для цього зручно використовувати:
input.value — поточне значення поля;
input.validity — стан вбудованої валідації;
input.setCustomValidity(message) — встановлення власної помилки;
input.reportValidity() — показ повідомлення браузера.
Якщо передати порожній рядок у setCustomValidity, власну помилку буде скасовано:
passwordConfirmation.setCustomValidity("");Якщо передати текст, поле стане невалідним:
passwordConfirmation.setCustomValidity("Паролі не збігаються");Нижче наведено самодостатній приклад. Він:
перевіряє ім’я, електронну пошту та пароль;
перевіряє збіг паролів;
скасовує стандартне надсилання;
читає дані через FormData;
показує повідомлення про успішне надсилання.
<!DOCTYPE html>
<html lang="uk">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Реєстрація</title>
<style>
body {
font-family: sans-serif;
max-width: 480px;
margin: 40px auto;
padding: 0 16px;
}
form {
display: grid;
gap: 16px;
}
label {
display: grid;
gap: 6px;
}
input {
padding: 8px;
font-size: 16px;
}
button {
padding: 10px;
cursor: pointer;
}
.error {
color: #b00020;
min-height: 20px;
}
.success {
color: #087f23;
}
</style>
</head>
<body>
<h1>Створення облікового запису</h1>
<form id="registration-form" novalidate>
<label for="name">Ім’я</label>
<input
id="name"
name="name"
type="text"
required
minlength="2"
autocomplete="name"
>
<label for="email">Електронна пошта</label>
<input
id="email"
name="email"
type="email"
required
autocomplete="email"
>
<label for="password">Пароль</label>
<input
id="password"
name="password"
type="password"
required
minlength="8"
autocomplete="new-password"
>
<label for="password-confirmation">Підтвердження пароля</label>
<input
id="password-confirmation"
name="passwordConfirmation"
type="password"
required
autocomplete="new-password"
>
<button type="submit">Зареєструватися</button>
<p id="form-message" class="error" role="status"></p>
</form>
<script>
const form = document.querySelector("#registration-form");
const nameInput = document.querySelector("#name");
const emailInput = document.querySelector("#email");
const passwordInput = document.querySelector("#password");
const confirmationInput = document.querySelector("#password-confirmation");
const message = document.querySelector("#form-message");
function validatePasswords() {
if (confirmationInput.value !== passwordInput.value) {
confirmationInput.setCustomValidity("Паролі не збігаються");
} else {
confirmationInput.setCustomValidity("");
}
}
passwordInput.addEventListener("input", validatePasswords);
confirmationInput.addEventListener("input", validatePasswords);
form.addEventListener("submit", (event) => {
event.preventDefault();
message.textContent = "";
message.className = "error";
validatePasswords();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
// Не виводьте справжні паролі в консоль у production-коді
console.log({
name: data.name,
email: data.email
});
message.textContent = `Дякуємо, ${data.name.trim()}! Форму успішно оброблено.`;
message.className = "success";
form.reset();
confirmationInput.setCustomValidity("");
});
</script>
</body>
</html>Атрибут novalidate у прикладі вимикає автоматичне показування стандартних повідомлень браузера під час надсилання. Водночас обмеження полів все одно доступні через checkValidity() і reportValidity().
Якщо потрібно повністю залишити стандартну поведінку браузера, novalidate можна прибрати.
checkValidity()Метод повертає true, якщо форма та всі її поля валідні:
if (form.checkValidity()) {
console.log("Дані коректні");
} else {
console.log("Є помилки");
}Цей метод лише перевіряє стан і не показує повідомлення користувачу.
reportValidity()Метод перевіряє форму та показує стандартне повідомлення для першого невалідного поля:
form.reportValidity();checkValidity() для окремого поляif (!emailInput.checkValidity()) {
console.log("Електронна пошта має неправильний формат");
}validityОб’єкт validity містить детальну інформацію про помилку:
if (emailInput.validity.valueMissing) {
console.log("Поле обов’язкове");
}
if (emailInput.validity.typeMismatch) {
console.log("Неправильний формат електронної пошти");
}
if (passwordInput.validity.tooShort) {
console.log("Пароль надто короткий");
}Поширені властивості:
valueMissing — не заповнено обов’язкове поле;
typeMismatch — значення не відповідає типу;
tooShort і tooLong — неправильна довжина;
rangeUnderflow і rangeOverflow — значення поза діапазоном;
patternMismatch — значення не відповідає pattern;
customError — встановлено власну помилку;
valid — поле повністю валідне.
Значення можна читати безпосередньо з полів:
const name = nameInput.value.trim();
const email = emailInput.value.trim();Для форми з багатьма полями зручніше використати FormData:
const formData = new FormData(form);
console.log(formData.get("name"));
console.log(formData.get("email"));FormData використовує значення атрибутів name, тому поле без name не буде включене до даних форми.
Перетворення на звичайний об’єкт:
const data = Object.fromEntries(new FormData(form));
console.log(data);Якщо кілька полів мають однакове ім’я, наприклад група прапорців, використовуйте getAll():
const formData = new FormData(form);
const selectedSkills = formData.getAll("skills");
console.log(selectedSkills);Після перевірки дані можна надіслати через fetch:
form.addEventListener("submit", async (event) => {
event.preventDefault();
if (!form.checkValidity()) {
form.reportValidity();
return;
}
const formData = new FormData(form);
try {
const response = await fetch("/api/register", {
method: "POST",
body: formData
});
if (!response.ok) {
throw new Error("Не вдалося надіслати форму");
}
console.log("Дані надіслано");
} catch (error) {
console.error(error);
}
});Під час надсилання FormData не потрібно вручну встановлювати заголовок Content-Type. Браузер сам додасть правильний тип разом із необхідним boundary.
Якщо сервер очікує JSON, дані можна перетворити:
const data = Object.fromEntries(new FormData(form));
const response = await fetch("/api/register", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});Паролі та інші конфіденційні дані не слід виводити в консоль або зберігати в localStorage. Остаточна перевірка даних завжди має виконуватися на сервері, оскільки клієнтський JavaScript можна змінити або обійти.
Повідомлення про помилки мають бути зрозумілими й пов’язаними з відповідним полем.
<label for="email">Електронна пошта</label>
<input
id="email"
name="email"
type="email"
aria-describedby="email-error"
required
>
<p id="email-error"></p>Якщо поле невалідне, можна додати атрибути:
emailInput.setAttribute("aria-invalid", "true");Після виправлення помилки:
emailInput.setAttribute("aria-invalid", "false");Для повідомлення про загальний результат форми корисним є role="status" або aria-live="polite". Це дозволяє допоміжним технологіям оголошувати зміни користувачу.
click замість submitbutton.addEventListener("click", handler);Такий підхід не враховує надсилання форми клавішею Enter. Обробляйте подію submit самої форми.
preventDefault() після перевіркиЯкщо спочатку виконати асинхронний код або іншу логіку, а preventDefault() викликати пізніше, браузер може вже розпочати стандартне надсилання.
Правильно:
form.addEventListener("submit", (event) => {
event.preventDefault();
// Подальша логіка
});nameПоле з id, але без name, доступне через DOM, проте не потрапляє до FormData.
<input id="email" type="email">Правильно:
<input id="email" name="email" type="email">Користувач може вимкнути JavaScript, змінити запит або надіслати його безпосередньо на сервер. Клієнтська перевірка покращує взаємодію, але не є захистом.
Пробіли на початку та в кінці можуть спричинити несподівані результати:
const name = nameInput.value.trim();
const email = emailInput.value.trim();Водночас не варто бездумно застосовувати trim() до всіх значень. Наприклад, пробіли можуть бути значущими для деяких текстових даних або паролів.
Не виводьте паролі, токени чи інші секрети в консоль, повідомлення або URL.
Створіть форму входу з такими полями:
електронна пошта;
пароль;
прапорець «Запам’ятати мене».
Реалізуйте:
вбудовану перевірку обов’язкових полів;
перевірку мінімальної довжини пароля;
скасування стандартного надсилання;
виведення даних через FormData;
повідомлення про успішну або невдалу обробку.
Додатково перевірте, як зміниться поведінка, якщо прибрати event.preventDefault().
Подію submit потрібно обробляти на елементі <form>.
event.preventDefault() скасовує стандартне надсилання та перезавантаження сторінки.
HTML-атрибути required, type, minlength, min, max і pattern забезпечують базову валідацію.
checkValidity() перевіряє форму, а reportValidity() додатково показує повідомлення браузера.
setCustomValidity() дає змогу створювати власні правила перевірки.
FormData зручно використовувати для отримання значень полів.
Атрибут name необхідний для включення поля до даних форми.
Клієнтська валідація не замінює перевірку на сервері.
Повідомлення про помилки мають бути доступними та зрозумілими користувачу.