Формы и валидация в JavaScript: обработка ввода

Содержание

О проверке кода. Примеры не запускались в браузере — в отличие от материалов по Node.js с фактическим выводом. Говорим прямо, а не ставим бейдж «проверено».

Формы — главный способ получить данные от пользователя. Их обработка в JavaScript строится вокруг события submit и проверки ввода. Разберём полный цикл: перехват, чтение, валидацию, отправку.

Перехват отправки

const form = document.querySelector('#signup');

form.addEventListener('submit', (event) => {
  event.preventDefault();              // отменяем перезагрузку страницы
  // теперь обрабатываем данные сами
});

Слушают событие submit на самой форме и вызывают preventDefault. По умолчанию отправка формы перезагружает страницу — в приложении на JavaScript это не нужно, данные шлют через fetch. Обработчик вешают именно на submit формы, а не на click кнопки: submit срабатывает и при нажатии Enter в поле.

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

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

  // FormData собирает все поля по атрибуту name
  const data = Object.fromEntries(new FormData(form));
  // { email: 'a@b.ru', password: '123', name: 'Аня' }

  console.log(data.email);
});

FormData собирает все поля формы по атрибуту name, а Object.fromEntries превращает их в обычный объект — удобно отправлять как JSON. Для одного поля можно и напрямую: form.elements.email.value или через querySelector. FormData также умеет файлы и сразу подходит для отправки multipart/form-data.

Встроенная валидация HTML5

Многое браузер проверяет сам, без JavaScript:

<input type="email" required>              <!-- обязательное, формат email -->
<input type="text" minlength="3" maxlength="20">
<input type="number" min="18" max="100">
<input type="text" pattern="[A-Za-z]+">    <!-- по регулярке -->
// прочитать результат встроенной проверки
if (!input.checkValidity()) {
  console.log(input.validationMessage);    // готовый текст ошибки от браузера
}
input.validity.valueMissing;               // true, если required пустое
input.validity.typeMismatch;               // true, если формат не тот

Атрибуты required, type="email", min, pattern — это встроенная валидация, которую браузер выполняет сам. JavaScript читает её результат через checkValidity() и input.validity, не проверяя базовые правила вручную. Это экономит код: не надо писать регулярку для email, если хватает type="email".

Своя валидация

Когда встроенных правил мало (совпадение паролей, проверка на сервере), пишут свою:

function validate(data) {
  const errors = {};

  if (!data.email.includes('@')) {
    errors.email = 'Некорректный email';
  }
  if (data.password.length < 8) {
    errors.password = 'Минимум 8 символов';
  }
  if (data.password !== data.passwordConfirm) {
    errors.passwordConfirm = 'Пароли не совпадают';
  }

  return errors;   // { } если всё ок
}

Своя проверка возвращает объект ошибок по полям. Функция чистая — принимает данные, возвращает ошибки, ничего не трогает в DOM. Это упрощает тестирование и повторное использование.

Показ ошибок

form.addEventListener('submit', (event) => {
  event.preventDefault();
  const data = Object.fromEntries(new FormData(form));
  const errors = validate(data);

  // очистить прошлые ошибки
  form.querySelectorAll('.error').forEach(el => el.textContent = '');

  if (Object.keys(errors).length > 0) {
    // показать ошибки рядом с полями
    for (const [field, message] of Object.entries(errors)) {
      const errorEl = form.querySelector(`[data-error="${field}"]`);
      if (errorEl) errorEl.textContent = message;
    }
    return;   // не отправляем
  }

  submitForm(data);   // всё валидно — отправляем
});

Ошибки показывают рядом с полями: находят элемент для сообщения и пишут текст через textContent (не innerHTML — это пользовательский контекст). Перед показом чистят прошлые ошибки. Object.entries перебирает пары «поле — сообщение».

Отправка данных

async function submitForm(data) {
  try {
    const response = await fetch('/api/signup', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });
    if (!response.ok) throw new Error(`Ошибка ${response.status}`);
    form.reset();                        // очистить форму
    showSuccess('Готово!');
  } catch (error) {
    showError('Не удалось отправить. Попробуйте позже.');
  }
}

Валидные данные уходят POST-запросом с JSON, ошибки ловятся try/catch. После успеха — form.reset() очищает поля.

Главное правило безопасности

Валидация: клиент и сервер

Клиентская — для удобства

Быстрая обратная связь

  • Мгновенная подсказка без запроса
  • Улучшает UX
  • Экономит запросы к серверу
  • НО легко обходится

Серверная — для безопасности

Единственная надёжная

  • Клиентский код можно отключить
  • Запрос можно подделать напрямую
  • Сервер проверяет ВСЕГДА
  • Никогда не доверяй данным клиента

Клиентская валидация не заменяет серверную. Она нужна для удобства — мгновенная подсказка без обращения к серверу. Но её легко обойти: отключить JavaScript или отправить запрос напрямую. Поэтому сервер проверяет данные всегда, независимо от клиента. Правило простое: клиент — для UX, сервер — для безопасности, доверять данным клиента нельзя.


Смежные темы: события DOM — submit и preventDefault; fetch — отправка данных; методы Object — FormData в объект; валидация в Express — серверная сторона. Полный список — в уроках JavaScript.

Частые вопросы

Как перехватить отправку формы в JavaScript?
Повесить обработчик на событие submit формы и вызвать event.preventDefault(), чтобы отменить стандартную перезагрузку страницы. После этого данные читают и обрабатывают через JavaScript, например отправляют fetch-запросом.
Как прочитать значения полей формы?
Через FormData: new FormData(form) собирает все поля по атрибуту name. Object.fromEntries превращает их в обычный объект. Либо обращаются к конкретному полю через form.elements.имя или querySelector.
Нужна ли валидация на клиенте, если есть на сервере?
Клиентская валидация улучшает удобство — мгновенная подсказка без запроса к серверу. Но она не заменяет серверную: клиентский код можно обойти. Правило: клиент для удобства, сервер для безопасности, проверять надо всегда на обоих.
Что такое встроенная валидация HTML5?
Атрибуты required, type email, min, max, pattern у полей, которые браузер проверяет сам. JavaScript читает результат через input.validity и checkValidity, что избавляет от ручной проверки многих базовых правил.
Как показать сообщение об ошибке рядом с полем?
Найти или создать элемент для ошибки рядом с полем, записать в него текст через textContent и переключить класс. Текст ошибки берут из своей логики или из input.validationMessage встроенной проверки.