Свойство form.elements в JavaScript
Свойство form.elements содержит элементы управления, связанные с конкретной формой. Через него можно получить поле по индексу, атрибуту name или id, а затем прочитать или изменить нужное DOM-свойство.
const form = document.querySelector('.order-form');
const emailInput = form.elements.email;
console.log(emailInput.value);
form.elements возвращает не готовые значения формы, а коллекцию самих элементов. Поэтому после получения поля код обращается к его value, checked, files или другому подходящему свойству.
elements является свойством, а не методом. Его читают без круглых скобок: form.elements.
- Форма для примеров
- Что содержит form.elements
- Доступ по индексу и имени
- Элементы с одинаковым name
- Чтение значений полей
- Поля за пределами form
- Живая коллекция
- Отличие от querySelectorAll()
- Итого
Форма для примеров
Создадим форму заказа с одиночными полями и группами переключателей:
<form class="order-form" id="order-form">
<label>
Имя
<input name="customerName" type="text" required>
</label>
<label>
Электронная почта
<input name="email" type="email" required>
</label>
<fieldset>
<legend>Способ доставки</legend>
<label>
<input
name="delivery"
type="radio"
value="courier"
checked
>
Курьер
</label>
<label>
<input name="delivery" type="radio" value="pickup">
Самовывоз
</label>
</fieldset>
<fieldset>
<legend>Дополнительно</legend>
<label>
<input name="extras" type="checkbox" value="gift-wrap">
Подарочная упаковка
</label>
<label>
<input name="extras" type="checkbox" value="card">
Открытка
</label>
</fieldset>
<button type="submit">Оформить заказ</button>
</form>
<label>
Промокод
<input name="promo" form="order-form" type="text">
</label>
Поле промокода расположено после закрывающего тега form, но связано с формой атрибутом form=“order-form”. Поэтому оно также будет доступно в orderForm.elements.
Что содержит form.elements
Получим форму и её коллекцию элементов:
const orderForm = document.querySelector('.order-form');
const controls = orderForm.elements;
console.log(controls);
console.log(controls.length);
Объект controls является коллекцией HTMLFormControlsCollection. Элементы в ней расположены в порядке документа.
К основным элементам коллекции относятся связанные с формой button, fieldset, input, object, output, select и textarea. Вложенность не мешает: поля внутри fieldset также относятся к форме.
Элементы label и option в form.elements не входят. Отключённое поле с атрибутом disabled остаётся в коллекции, хотя при обычной отправке формы его значение не передаётся.
input type=“image”по историческим причинам не входит вform.elements. Если такой элемент нужно получить, используйте обычный DOM-поиск.
Доступ по индексу и имени
Элемент можно получить по числовому индексу или методом item():
const firstControl = orderForm.elements[0];
const sameControl = orderForm.elements.item(0);
console.log(firstControl === sameControl); // true
Индекс зависит от порядка разметки. Если перед полем добавить другой элемент управления, его позиция изменится. Для конкретного поля обычно надёжнее использовать имя:
const emailInput = orderForm.elements.email;
const sameEmailInput = orderForm.elements['email'];
const emailByMethod = orderForm.elements.namedItem('email');
console.log(emailInput === sameEmailInput); // true
console.log(emailInput === emailByMethod); // true
Именованный доступ ищет совпадение по атрибуту name или id. Если подходящего элемента нет, метод namedItem() возвращает null.
Для полей формы лучше задавать name. Он не только позволяет получить элемент через коллекцию, но и задаёт имя его значения при отправке формы. Поле без name всё равно может находиться в elements по индексу или id, но его значение не получит имени в данных формы.
Квадратные скобки подходят для имён с дефисом и других строк, которые неудобно записывать после точки:
const phoneInput = orderForm.elements['phone-number'];
У коллекции уже есть свойства и методы, например length, item и namedItem. Если поле получило одно из таких имён, запись через точку вернёт встроенное свойство, а не элемент. В этом случае используйте namedItem():
<form class="size-form">
<input name="length" type="number">
</form>
const sizeForm = document.querySelector('.size-form');
console.log(sizeForm.elements.length); // 1
const lengthInput = sizeForm.elements.namedItem('length');
Элементы с одинаковым name
Если имя принадлежит нескольким элементам, коллекция возвращает группу RadioNodeList. Несмотря на название, такая группа может содержать не только radio-кнопки.
В форме из примера две radio-кнопки имеют имя delivery:
const deliveryGroup = orderForm.elements.delivery;
console.log(deliveryGroup.length); // 2
console.log(deliveryGroup.value); // courier
У radio-группы свойство value содержит значение выбранной кнопки. Если ни одна кнопка не выбрана, оно возвращает пустую строку. Значение можно и присвоить всей группе:
deliveryGroup.value = 'pickup';
console.log(deliveryGroup.value); // pickup
Для нескольких checkbox с одинаковым именем нужно проверить каждый элемент отдельно. Свойство value группы не собирает значения отмеченных checkbox.
const extraCheckboxes = orderForm.elements.extras;
const selectedExtras = Array.from(extraCheckboxes)
.filter(function (checkbox) {
return checkbox.checked;
})
.map(function (checkbox) {
return checkbox.value;
});
console.log(selectedExtras);
Возвращаемый тип зависит от количества совпадений. Одно поле с указанным именем возвращается как сам элемент, а несколько полей - как группа. Это важно учитывать, если разметка формы может изменяться.
Чтение значений полей
С помощью form.elements удобно получить элементы, а затем выбрать подходящее свойство для каждого типа поля:
orderForm.addEventListener('submit', function (event) {
event.preventDefault();
const form = event.currentTarget;
const elements = form.elements;
const selectedExtras = Array.from(elements.extras)
.filter(function (checkbox) {
return checkbox.checked;
})
.map(function (checkbox) {
return checkbox.value;
});
const order = {
customerName: elements.customerName.value.trim(),
email: elements.email.value.trim(),
delivery: elements.delivery.value,
extras: selectedExtras,
promo: elements.promo.value.trim(),
};
console.log(order);
});
Коллекция не преобразует типы и не решает, какое свойство нужно прочитать. Текст находится в value, состояние отдельного checkbox - в checked, а выбранные файлы - в files. Эти значения код получает уже у конкретных элементов.
Поля за пределами form
Расположение между открывающим и закрывающим тегами form - не единственный способ связать поле с формой. Атрибут form принимает id нужной формы:
<form id="subscription-form">
<button type="submit">Подписаться</button>
</form>
<input
name="email"
type="email"
form="subscription-form"
required
>
const subscriptionForm = document.querySelector('#subscription-form');
console.log(subscriptionForm.elements.email);
Такое поле входит в form.elements, участвует в проверке и отправке этой формы, хотя находится в другом месте разметки. Если вложенному полю через атрибут form назначена другая форма, в коллекцию родительской формы оно не попадёт.
Живая коллекция
HTMLFormControlsCollection является живой коллекцией. Она автоматически отражает добавление, удаление и изменение связи элементов с формой.
const controls = orderForm.elements;
const initialLength = controls.length;
const commentInput = document.createElement('input');
commentInput.name = 'comment';
commentInput.type = 'text';
orderForm.append(commentInput);
console.log(controls.length === initialLength + 1); // true
console.log(controls.comment === commentInput); // true
Переменную controls не пришлось создавать заново. После вставки поля та же коллекция уже содержит новый элемент.
При изменении DOM во время перебора живая коллекция может менять длину и индексы. Если нужен неизменяемый список на текущий момент, создайте обычный массив:
const controlsSnapshot = Array.from(orderForm.elements);
Отличие от querySelectorAll()
form.elements и querySelectorAll() могут находить поля, но работают по разным правилам.
form.elements | form.querySelectorAll() |
|---|---|
| Содержит элементы управления, связанные с формой | Ищет потомков формы по CSS-селектору |
Учитывает внешние поля с подходящим атрибутом form | Не включает элементы за пределами формы |
| Возвращает живую коллекцию | Возвращает статический NodeList |
Поддерживает доступ по name и id | Позволяет задать любой CSS-селектор |
Для обращения к известному полю формы обычно удобно использовать form.elements. Если нужно найти только элементы определённого типа, класса или состояния, CSS-селектор может быть понятнее:
const checkedExtras = orderForm.querySelectorAll(
'input[name="extras"]:checked',
);
Итого
Свойство form.elements возвращает живую коллекцию HTMLFormControlsCollection с элементами управления, связанными с формой. Поле можно получить по индексу, через квадратные скобки, методом item() или namedItem(). Для постоянного обращения к конкретному полю обычно используют его name.
Если одно имя принадлежит нескольким элементам, результатом становится группа RadioNodeList. У radio-группы можно читать и задавать value, а несколько checkbox нужно перебирать отдельно. Коллекция обновляется вместе с DOM и учитывает поля за пределами тега form, если они связаны с формой одноимённым атрибутом.