Получение данных формы в JavaScript
Данные формы можно получать по отдельным полям или собрать сразу в объект FormData. Первый способ удобен, когда нужны конкретные значения и их необходимо сразу преобразовать. Второй позволяет получить все подходящие поля формы по атрибутам name.
const form = document.querySelector('.profile-form');
const username = form.elements.username.value;
const formData = new FormData(form);
Оба способа читают текущее состояние формы: введённый текст, выбранные пункты и отмеченные переключатели.
- Форма для примеров
- Когда получать данные формы
- Получение данных через form.elements
- Получение данных через FormData
- Какие поля попадают в FormData
- Методы get(), getAll() и has()
- Перебор FormData
- Преобразование данных в объект
- Типы и подготовка значений
- Получение выбранного файла
- Итого
Форма для примеров
Создадим форму профиля с полями разных типов:
<form class="profile-form">
<label>
Имя
<input name="username" type="text" required>
</label>
<label>
Возраст
<input name="age" type="number" min="14">
</label>
<label>
Город
<select name="city">
<option value="">Выберите город</option>
<option value="moscow">Москва</option>
<option value="kazan">Казань</option>
</select>
</label>
<fieldset>
<legend>Формат занятий</legend>
<label>
<input name="studyFormat" type="radio" value="online" checked>
Онлайн
</label>
<label>
<input name="studyFormat" type="radio" value="offline">
Очно
</label>
</fieldset>
<fieldset>
<legend>Интересующие темы</legend>
<label>
<input name="topics" type="checkbox" value="html">
HTML
</label>
<label>
<input name="topics" type="checkbox" value="css">
CSS
</label>
<label>
<input name="topics" type="checkbox" value="javascript">
JavaScript
</label>
</fieldset>
<label>
<input name="newsletter" type="checkbox" value="yes">
Получать рассылку
</label>
<button type="submit">Сохранить</button>
</form>
Атрибут name задаёт имя каждого значения. Он нужен и для доступа через form.elements, и для включения поля в FormData.
У radio-кнопок и checkbox одной группы имя повторяется, а value различается. Благодаря этому данные сохраняют не только факт выбора, но и выбранный вариант.
Когда получать данные формы
Обычно данные читают в обработчике события submit. В этот момент пользователь уже заполнил поля и запустил отправку формы.
const profileForm = document.querySelector('.profile-form');
profileForm.addEventListener('submit', function (event) {
event.preventDefault();
const form = event.currentTarget;
const formData = new FormData(form);
console.log(formData);
});
event.currentTarget содержит форму, которой назначен обработчик. Метод preventDefault() отменяет обычную отправку и перезагрузку страницы, но сам ничего не сохраняет. Дальнейшую обработку данных должен выполнить код.
Перед событием submit браузер проверяет HTML-ограничения, например required и min. Если поле не прошло проверку, обработчик не запустится.
Создать FormData можно и без отправки, например по нажатию обычной кнопки предпросмотра. Объект получает значения в момент вызова new FormData(form). Если пользователь после этого изменит поле, уже созданный объект автоматически не обновится.
Получение данных через form.elements
Свойство elements позволяет обратиться к полям формы по их name:
const usernameInput = profileForm.elements.username;
const ageInput = profileForm.elements.age;
const citySelect = profileForm.elements.city;
const studyFormatGroup = profileForm.elements.studyFormat;
const newsletterCheckbox = profileForm.elements.newsletter;
console.log(usernameInput.value);
console.log(ageInput.valueAsNumber);
console.log(citySelect.value);
console.log(studyFormatGroup.value);
console.log(newsletterCheckbox.checked);
Через form.elements код получает сами элементы, поэтому можно выбрать подходящее свойство для каждого типа поля. Текст и значение select находятся в value, число можно получить через valueAsNumber, а состояние одиночного checkbox - через checked.
Для нескольких checkbox с одинаковым именем возвращается группа. Соберём значения отмеченных элементов:
const topicCheckboxes = profileForm.elements.topics;
const selectedTopics = [...topicCheckboxes]
.filter(function (checkbox) {
return checkbox.checked;
})
.map(function (checkbox) {
return checkbox.value;
});
console.log(selectedTopics); // например, ['html', 'javascript']
Получение через elements удобно, когда полей немного или для каждого значения нужна своя обработка. Например, число должно остаться числом, а состояние checkbox требуется получить как true или false.
Получение данных через FormData
Конструктор FormData собирает текущие значения элементов формы:
const formData = new FormData(profileForm);
Получившийся объект хранит пары «имя - значение». Именем служит атрибут name, а значение берётся из текущего состояния поля.
Например, после заполнения формы внутри FormData могут находиться такие пары:
username: Анна
age: 24
city: kazan
studyFormat: online
topics: html
topics: javascript
newsletter: yes
Имя topics встречается дважды, потому что пользователь отметил два checkbox одной группы. FormData сохраняет повторяющиеся имена и порядок полей.
FormData только собирает данные. Создание объекта не отправляет их на сервер и не сохраняет в браузере.
Какие поля попадают в FormData
Не каждый элемент внутри form становится частью данных. Основные правила удобно представить в таблице:
| Поле | Результат |
|---|---|
Текстовый input, textarea, обычный select | Строка, в том числе пустая |
input type=“number” | Строка, а не число |
| Выбранная radio-кнопка | Её value |
| Отмеченный checkbox | Его value |
| Снятый checkbox или невыбранная radio-кнопка | Не добавляется |
select multiple | Отдельная пара для каждого выбранного пункта |
input type=“file” | Объект File |
Поле без name | Не добавляется |
Поле с disabled | Не добавляется |
Поле с атрибутом readonly остаётся частью данных. Этот атрибут запрещает редактирование, но в отличие от disabled не исключает значение из формы.
При вызове new FormData(form) кнопки отправки не добавляются. Если нужно включить name и value кнопки, которая запустила отправку, её передают вторым аргументом:
profileForm.addEventListener('submit', function (event) {
event.preventDefault();
const formData = event.submitter
? new FormData(profileForm, event.submitter)
: new FormData(profileForm);
});
Такой вариант имеет смысл, когда у формы несколько кнопок отправки с разными значениями. Проверка нужна на случай, если отправка была запущена программно без конкретной кнопки.
Методы get(), getAll() и has()
Метод get() возвращает первое значение с указанным именем. Если такого имени нет, результатом будет null:
const username = formData.get('username');
const city = formData.get('city');
console.log(username); // Анна
console.log(city); // kazan
Для повторяющихся имён используют getAll(). Метод всегда возвращает массив:
const topics = formData.getAll('topics');
console.log(topics); // ['html', 'javascript']
Если ни один checkbox группы не отмечен, массив будет пустым. Вызов formData.get(‘topics’) вернул бы только первое выбранное значение и потерял остальные.
Метод has() проверяет, есть ли имя в данных:
const getsNewsletter = formData.has('newsletter');
console.log(getsNewsletter); // true или false
В данном случае результат показывает состояние checkbox, потому что снятый флажок не попадает в FormData. Если поле может присутствовать с пустой строкой, has() сообщит только о наличии имени, а не о заполненности значения.
Перебор FormData
Объект FormData является итерируемым. Все пары можно получить в цикле for...of:
for (const [name, value] of formData) {
console.log(name, value);
}
На каждой итерации переменная name содержит имя поля, а value - строку или объект File. Поля с одинаковым именем будут выведены несколько раз.
Простой вызов console.log(formData) не во всех инструментах разработчика удобно показывает содержимое. Перебор позволяет увидеть фактические пары:
console.log([...formData]);
// [
// ['username', 'Анна'],
// ['age', '24'],
// ['topics', 'html']
// ]
Преобразование данных в объект
Для простой формы FormData можно преобразовать в обычный объект через Object.fromEntries():
const data = Object.fromEntries(formData);
console.log(data);
Такой объект удобнее просматривать и использовать в логике приложения. Однако у преобразования есть важное ограничение: свойства объекта не могут хранить несколько значений под одним ключом. Если имя повторяется, останется последнее значение.
Поэтому массивы нужно получить через getAll() и добавить отдельно:
const data = Object.fromEntries(formData);
data.topics = formData.getAll('topics');
console.log(data.topics); // ['html', 'javascript']
Object.fromEntries() не меняет типы данных. Возраст останется строкой, а выбранный файл - объектом File.
Типы и подготовка значений
Значения обычных полей внутри FormData являются строками. Атрибуты type=“number” и value=“yes” не превращают их в число или логическое значение автоматически.
Для данных приложения часто полезно собрать отдельный объект с нужными типами:
const ageInput = profileForm.elements.age;
const profile = {
username: profileForm.elements.username.value.trim(),
age: ageInput.value === '' ? null : ageInput.valueAsNumber,
city: formData.get('city'),
studyFormat: formData.get('studyFormat'),
topics: formData.getAll('topics'),
newsletter: profileForm.elements.newsletter.checked,
};
console.log(profile);
Здесь имя очищается от пробелов по краям, возраст становится числом или null, выбранные темы сохраняются массивом, а состояние рассылки - логическим значением.
Такое преобразование особенно полезно перед проверкой данных или вычислениями. При этом данные, полученные от пользователя, всё равно необходимо проверять на сервере.
Получение выбранного файла
FormData умеет хранить не только строки, но и файлы. Добавим отдельное поле:
<form class="document-form">
<label>
Резюме
<input name="resume" type="file" accept=".pdf">
</label>
</form>
const documentForm = document.querySelector('.document-form');
const documentData = new FormData(documentForm);
const resume = documentData.get('resume');
if (resume instanceof File && resume.size > 0) {
console.log(resume.name);
console.log(resume.type);
console.log(resume.size);
}
Метод get() возвращает объект File. Проверка size > 0 помогает отличить выбранный файл от пустого значения поля.
Итого
form.elements даёт доступ к отдельным элементам формы и их DOM-свойствам. Этот способ подходит, когда нужно сразу получить число, логическое значение или обработать несколько конкретных полей.
FormData собирает именованные и доступные поля целиком. Значения получают через get(), повторяющиеся значения - через getAll(), а наличие имени проверяют методом has(). Объект можно перебрать или преобразовать через Object.fromEntries(), учитывая, что обычные значения остаются строками, а повторяющиеся имена требуют отдельной обработки.