JavaScript и HTML-формы: управление событиями и элементами

Раздел: Веб-разработка -> DOM и события

Работа с формами в DOM и событиях

Формы - основной способ сбора данных от пользователя. JavaScript позволяет перехватывать отправку, проверять значения полей, менять состояние элементов и отправлять данные без перезагрузки. Далее рассмотрены основные приёмы с примерами кода и указанием типичных ошибок.

Основной способ: перехват отправки через addEventListener

Как предотвратить перезагрузку страницы при отправке формы и получить данные полей?

Самый надёжный метод - повесить обработчик события submit на элемент form и вызвать event.preventDefault(). Затем прочитать значения через form.elements или по ID.

document.getElementById('myForm').addEventListener('submit', function(event) {
  event.preventDefault();
  const form = event.target;
  const name = form.elements['userName'].value;
  const email = form.elements['email'].value;
  console.log('Имя:', name, 'Email:', email);
});

Javascript страницы (javascript на страницах)

Пояснение: event.preventDefault() отменяет стандартную отправку, после чего можно выполнить свою логику (например, AJAX-запрос). Для доступа к полям используется коллекция form.elements - она содержит все элементы управления с атрибутами name.

Типичная ошибка: забыть указать event.preventDefault(), из-за чего страница перезагружается и данные теряются. Решение: всегда ставить этот вызов первым в обработчике.

Проблема: обращение к полям по индексу или неверному имени. Решение: использовать form.elements.namedItem('name') или проверять существование элемента.

Вариант с использованием атрибута onsubmit

Как можно обработать отправку формы без addEventListener?

Старый способ - атрибут onsubmit в HTML. Он возвращает false для отмены отправки.

<form onsubmit="return handleSubmit(event)">
  <input name="login">
  <button type="submit">Отправить</button>
</form>
<script>
function handleSubmit(event) {
  event.preventDefault();
  // ...
  return false;
}
</script>

кнопки js (кнопки в javascript)

Пояснение: функция вызывается при отправке. Если она возвращает false, форма не отправляется. Важно также вызвать event.preventDefault() для совместимости с некоторыми браузерами.

Недостаток: смешивание HTML и JavaScript, сложнее поддерживать. Не рекомендуется для современных проектов.

Вариант с передачей объекта FormData

Как удобно собрать все данные формы в один объект для отправки?

Использование конструктора FormData, который автоматически извлекает значения всех полей по их атрибутам name.

document.getElementById('myForm').addEventListener('submit', function(e) {
  e.preventDefault();
  const formData = new FormData(this);
  const data = Object.fromEntries(formData);
  console.log(data); // {userName: '...', email: '...'}
});

Js удалить (удаление элементов в javascript)

Пояснение: FormData удобен для отправки через fetch как multipart/form-data. Object.fromEntries преобразует пары ключ-значение в обычный объект.

Проблема: Object.fromEntries не поддерживается в очень старых браузерах. Решение: использовать цикл по formData.entries().

Валидация полей перед отправкой

Как проверить корректность e-mail или обязательность полей без встроенной HTML5-валидации?

В обработчике submit проверяем каждое поле и выводим ошибки. Используем event.preventDefault() при любой ошибке.

form.addEventListener('submit', function(e) {
  e.preventDefault();
  const email = form.elements['email'].value.trim();
  const errors = [];
  if (!email.includes('@')) {
    errors.push('Некорректный email');
  }
  if (errors.length) {
    alert(errors.join('\n'));
    return;
  }
  // отправка данных
});

Js forms (формы в javascript)

Пояснение: валидация выполняется вручную, что даёт полный контроль над сообщениями и логикой.

Типичная ошибка: забыть обрезку пробелов (trim()), что приводит к ложным ошибкам. Решение: всегда применять trim().

Динамическое добавление полей и их обработка

Как обрабатывать форму, в которую пользователь добавляет новые элементы через кнопку «Добавить еще»?

Использовать делегирование событий на контейнере или назначать обработчики каждому новому полю через addEventListener при создании.

const container = document.getElementById('fieldsContainer');
document.getElementById('addBtn').addEventListener('click', function() {
  const input = document.createElement('input');
  input.type = 'text';
  input.name = 'extra[]';
  container.appendChild(input);
});
form.addEventListener('submit', function(e) {
  e.preventDefault();
  const extras = form.elements['extra[]'];
  const values = Array.from(extras).map(el => el.value);
  console.log(values);
});

Пояснение: form.elements['extra[]'] возвращает коллекцию всех элементов с таким именем. Для работы с динамическими полями удобно использовать массивы.

Проблема: если поле одно, form.elements вернёт один узел, а не коллекцию. Решение: проверять наличие свойства length и всегда оборачивать в массив: [].concat(extras).

Расширенные примеры работы с формами

1. Отправка формы через fetch с JSON

Пример отправки данных без перезагрузки, сериализация в JSON.

Пример
document.getElementById('orderForm').addEventListener('submit', async function(e) {
  e.preventDefault();
  const formData = new FormData(this);
  const json = Object.fromEntries(formData.entries());
  try {
    const response = await fetch('/api/order', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify(json)
    });
    const result = await response.json();
    console.log('Успешно:', result);
  } catch (err) {
    console.error('Ошибка:', err);
  }
});

Результат в консоли (если сервер отвечает):

{ id: 123, status: 'created' }

2. Отправка формы с файлами (FormData + fetch)

Загрузка одного или нескольких файлов без перезагрузки.

Пример
document.getElementById('uploadForm').addEventListener('submit', async function(e) {
  e.preventDefault();
  const formData = new FormData(this); // файлы берутся из input[type=file]
  try {
    const res = await fetch('/upload', { method: 'POST', body: formData });
    const text = await res.text();
    console.log('Ответ сервера:', text);
  } catch (err) {
    console.error('Ошибка сети', err);
  }
});

Результат (предполагаемый ответ сервера):

Файл image.jpg загружен успешно

3. Поэтапная валидация с подсветкой полей

Проверка каждого поля при потере фокуса (blur) и подсветка ошибок.

Пример
const inputs = document.querySelectorAll('#registerForm input[required]');
inputs.forEach(input => {
  input.addEventListener('blur', function() {
    const errorSpan = this.nextElementSibling;
    if (!this.value.trim()) {
      this.style.borderColor = 'red';
      errorSpan.textContent = 'Поле обязательно';
    } else {
      this.style.borderColor = '';
      errorSpan.textContent = '';
    }
  });
});

HTML-структура для этого примера:

Пример
<form id="registerForm">
  <input name="username" required><span class="error"></span>
  <input name="email" type="email" required><span class="error"></span>
  <button>Зарегистрироваться</button>
</form>

Результат: при пустом поле после потери фокуса граница становится красной, появляется текст ошибки.

4. Программная смена типа отправки (GET вместо POST)

Перехват отправки и перенаправление браузера с собранными данными в строке запроса.

Пример
document.getElementById('searchForm').addEventListener('submit', function(e) {
  e.preventDefault();
  const formData = new FormData(this);
  const params = new URLSearchParams(formData);
  window.location.href = '/search?' + params.toString();
});

Результат: браузер переходит на /search?q=javascript&category=books.

5. Отмена отправки при повторном нажатии (защита от дублей)

Блокировка кнопки отправки после первого клика.

Пример
let submitting = false;
form.addEventListener('submit', async function(e) {
  if (submitting) {
    e.preventDefault();
    return;
  }
  submitting = true;
  const btn = this.querySelector('button[type="submit"]');
  btn.disabled = true;
  try {
    await fetch('/submit', { method: 'POST', body: new FormData(this) });
  } finally {
    submitting = false;
    btn.disabled = false;
  }
});

Результат: кнопка становится неактивной, пока выполняется запрос, и повторные нажатия игнорируются.

6. Получение данных из выпадающего списка (select)

Чтение выбранного значения и текста опции.

Пример
form.addEventListener('submit', function(e) {
  e.preventDefault();
  const select = this.elements['country'];
  const selectedValue = select.value;
  const selectedText = select.options[select.selectedIndex].text;
  console.log('Значение:', selectedValue, 'Текст:', selectedText);
});

Результат (если выбрана Италия):

Значение: IT, Текст: Италия

7. Работа с чекбоксами и радиокнопками

Сбор отмеченных значений.

Пример
form.addEventListener('submit', function(e) {
  e.preventDefault();
  const checkboxes = this.elements['hobbies'];
  const checked = Array.from(checkboxes).filter(cb => cb.checked).map(cb => cb.value);
  console.log('Хобби:', checked);
  const radio = this.elements['gender'];
  console.log('Пол:', radio.value); // значение выбранной радиокнопки
});

HTML для примера:

Пример
<input type="checkbox" name="hobbies" value="reading"> Чтение
<input type="checkbox" name="hobbies" value="sports"> Спорт
<input type="radio" name="gender" value="male"> Мужской
<input type="radio" name="gender" value="female"> Женский

Результат в консоли:

Хобби: ['reading', 'sports']
Пол: female

Формы в JavaScript - comments

En
Js forms (javascript)