Валидация форм на JavaScript

Free Preview
Продолжительность:

HTML-атрибут required даёт базовую проверку, но его возможностей быстро перестаёт хватать: нельзя задать собственные сообщения об ошибках, красиво выделить проблемное поле или проверить, соответствует ли номер телефона нужному формату. Для этого пишут валидацию на JavaScript.

Читаем значения полей

Для начала разберёмся, как получить то, что ввёл пользователь.

У текстовых полей (input[type=text], email, tel, textarea) значение берётся из свойства value:

const nameInput = document.querySelector('#name');
console.log(nameInput.value); // 'Иван Петров'
js

У чекбокса нас интересует не value, а checked — булево свойство:

const agreeCheckbox = document.querySelector('#agree');
console.log(agreeCheckbox.checked); // true или false
js

У радио-кнопок нужно найти ту, которая выбрана:

const selectedTour = document.querySelector('input[name="tour"]:checked');
console.log(selectedTour?.value); // 'classic' или 'premium', или undefined если не выбрано
js

Перехватываем отправку формы

Валидацию запускают в обработчике события submit. Важно вызвать e.preventDefault() — иначе страница перезагрузится до того, как мы успеем что-то проверить:

const form = document.querySelector('#contact-form');

form.addEventListener('submit', (e) => {
  e.preventDefault(); // останавливаем стандартную отправку

  const name = document.querySelector('#name').value.trim();
  const email = document.querySelector('#email').value.trim();

  if (!name) {
    console.log('Имя не заполнено');
    return;
  }

  // всё в порядке — можно отправлять
  console.log({ name, email });
});
js

.trim() убирает пробелы по краям — пользователь мог случайно нажать пробел, а поле при этом будет формально непустым.

Отображаем ошибки

Просто остановить отправку — недостаточно. Пользователь должен понять, что именно не так. Удобный подход: под каждым полем заранее разместить элемент для сообщения об ошибке, и показывать его при необходимости.

HTML:

<div class="form-field">
  <label for="name">Ваше имя</label>
  <input type="text" id="name" name="name">
  <span class="error-message" id="name-error"></span>
</div>
html

CSS:

.form-field input.invalid,
.form-field textarea.invalid,
.form-field select.invalid {
  border-color: #e53e3e;
}

.error-message {
  display: block;
  font-size: 13px;
  color: #e53e3e;
  margin-top: 4px;
  min-height: 18px; /* чтобы форма не прыгала при появлении текста */
}
css

JavaScript — функция для показа и скрытия ошибки:

function showError(inputEl, message) {
  inputEl.classList.add('invalid');
  const errorEl = document.querySelector(`#${inputEl.id}-error`);
  if (errorEl) errorEl.textContent = message;
}

function clearError(inputEl) {
  inputEl.classList.remove('invalid');
  const errorEl = document.querySelector(`#${inputEl.id}-error`);
  if (errorEl) errorEl.textContent = '';
}
js

Валидируем форму

Теперь можно написать полноценную проверку. Вынесем логику в отдельную функцию — удобнее и проще тестировать:

function validateForm() {
  let isValid = true;

  const nameInput = document.querySelector('#name');
  const emailInput = document.querySelector('#email');

  // Сбрасываем предыдущие ошибки
  clearError(nameInput);
  clearError(emailInput);

  // Проверяем имя
  if (!nameInput.value.trim()) {
    showError(nameInput, 'Пожалуйста, укажите ваше имя');
    isValid = false;
  }

  // Проверяем email
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailInput.value.trim()) {
    showError(emailInput, 'Пожалуйста, укажите email');
    isValid = false;
  } else if (!emailRegex.test(emailInput.value)) {
    showError(emailInput, 'Введите корректный email');
    isValid = false;
  }

  return isValid;
}

form.addEventListener('submit', (e) => {
  e.preventDefault();

  if (!validateForm()) return;

  // форма прошла проверку
  console.log('Отправляем данные...');
});
js

Регулярное выражение /^[^\s@]+@[^\s@]+\.[^\s@]+$/ — стандартная упрощённая проверка email. Для большинства задач её достаточно.

Валидация в реальном времени

Показывать ошибку только в момент отправки — нормально. Но удобнее убирать ошибку сразу, как пользователь начал исправлять поле. Для этого слушаем событие input:

nameInput.addEventListener('input', () => {
  if (nameInput.value.trim()) {
    clearError(nameInput);
  }
});
js

Или немного агрессивнее — проверять при потере фокуса (событие blur). Так ошибка появится, когда пользователь уйдёт с поля, не заполнив его:

nameInput.addEventListener('blur', () => {
  if (!nameInput.value.trim()) {
    showError(nameInput, 'Пожалуйста, укажите ваше имя');
  }
});
js

На практике часто комбинируют: blur — для показа ошибки, input — для её снятия.

FormData

Если полей в форме много, собирать значения по одному становится утомительно. Браузер предоставляет встроенный объект FormData, который сам собирает все поля формы:

const formData = new FormData(form);

console.log(formData.get('name'));   // значение поля name
console.log(formData.get('email'));  // значение поля email

// Преобразовать в обычный объект:
const data = Object.fromEntries(formData.entries());
console.log(data); // { name: '...', email: '...', ... }
js

Единственное условие — каждое поле должно иметь атрибут name.

В следующем уроке применим всё это на практике: создадим форму заявки на тур в Санкт-Петербург с полноценной валидацией и отправкой данных на сервер.