www.jQueryBook.ru - jQuery документация

 

 

 

 



Формы в jQuery: значения полей, чекбоксы, select и валидация

Опубликовано: 26.09.2026 · Обновлено: 26.09.2026 · Актуально для jQuery 3.7.1 и 4.0.0

Три вещи, которые нужно держать в голове при работе с формами в jQuery. Значение поля — это .val(): одна функция для текстовых полей, textarea и select. Состояние — checked у чекбокса, selected у option, disabled у любого поля — это не атрибут, а свойство, поэтому читать и менять его нужно через .prop(), а не .attr(). Собрать данные формы для отправки — .serialize() или .serializeArray() для обычных полей, FormData — если есть файлы. А проверка перед отправкой начинается не с плагина, а с обычных HTML5-атрибутов вроде required и pattern, которые браузер умеет проверять сам.

.val(): значения полей

.val() — единая точка входа для чтения и записи значения у текстовых полей, textarea и select, независимо от того, какой это тип поля. Без аргумента она читает текущее значение, с аргументом — устанавливает:

// Чтение
var name = $("#name").val();       // "Иван"
var comment = $("#comment").val(); // содержимое textarea

// Запись
$("#name").val("Пётр");
$("#comment").val("");

У select без атрибута multiple .val() возвращает значение выбранного option — атрибут value, если он задан, иначе текст пункта. У множественного select (<select multiple>) — массив значений всех выбранных option; если не выбрано ни одного, с jQuery 3.0 это пустой массив [] (в версиях до 3.0 в этом случае возвращался null).

<select id="langs" multiple>
  <option value="ru">Русский</option>
  <option value="en" selected>English</option>
  <option value="de" selected>Deutsch</option>
</select>

$("#langs").val(); // ["en", "de"]

Массив можно передать и на запись — так одним вызовом отмечаются нужные пункты множественного select, а также чекбоксы и radio с одинаковым name: элементы, чьё значение попало в массив, становятся отмеченными, остальные — снимаются.

// Отметить два конкретных чекбокса из набора, остальные — снять
$("input[name='topics']").val(["news", "sport"]);

С jQuery 1.4 вместо значения можно передать функцию — она вызывается для каждого элемента набора и получает индекс и текущее значение, а вернуть должна новое значение:

// Обрезать пробелы по краям во всех текстовых полях формы
$("#order-form input[type=text]").val(function (i, currentValue) {
  return currentValue.trim();
});

Установка значения через .val() (как и через нативное свойство value) не порождает событие change. Если на поле висит обработчик change — например, пересчёт итоговой суммы или сторонний плагин выбора даты, — после программной установки значения его нужно вызвать явно: $("#price").val(1200).trigger("change").

ЭлементЧто вернёт .val()
<input type="text">, <textarea>Строка с текущим содержимым
<input type="checkbox"> / radio (один элемент)Значение атрибута value (по умолчанию "on", если атрибут не указан) — не зависит от того, отмечен элемент или нет
Набор radio/checkbox с одним name, вызов на всей группеЗначение value первого элемента набора в DOM — для radio это почти никогда не то, что нужно; для получения отметки используйте :checked, см. ниже
<select> (одиночный)Значение выбранного option; если ни один option явно не помечен selected, браузер считает выбранным первый
<select multiple>Массив значений выбранных option; пустой массив, если ничего не выбрано (jQuery ≥ 3.0)

Чекбоксы и радиокнопки

Отметка чекбокса или radio — это не атрибут HTML, а булево свойство DOM-элемента, которое меняется при клике пользователя. Работать с ним нужно через .prop(), а не .attr():

// Прочитать
var checked = $("#agree").prop("checked"); // true / false
var checkedShort = $("#agree").is(":checked"); // то же самое

// Установить
$("#agree").prop("checked", true);
$("#agree").prop("checked", false);

«Отметить все» — распространённый паттерн: один чекбокс-переключатель управляет состоянием набора чекбоксов.

<input type="checkbox" id="toggle-all"> Выбрать все
<input type="checkbox" class="item" value="1">
<input type="checkbox" class="item" value="2">
<input type="checkbox" class="item" value="3">

<script>
$("#toggle-all").on("change", function () {
  $(".item").prop("checked", this.checked);
});
</script>

Для radio нужно не состояние конкретной кнопки, а значение той, что отмечена во всей группе. Селектор :checked в паре с именем группы решает это одним вызовом:

<input type="radio" name="pay-method" value="card" checked> Карта
<input type="radio" name="pay-method" value="cash"> Наличные

var method = $("input[name='pay-method']:checked").val(); // "card"

Тот же селектор работает и с чекбоксами — $("input[name='topics']:checked") вернёт jQuery-объект из всех отмеченных элементов набора; чтобы получить их значения списком, пройдитесь по коллекции через .map().

$(...).attr("checked") «врёт» не случайно, а по определению. HTML-атрибут checked — это только исходная разметка, она отвечает за свойство defaultChecked и не меняется от кликов пользователя. Текущее состояние — отдельное свойство DOM-элемента, и читать/писать его нужно через .prop() (про разницу с атрибутами — на странице .attr()). jQuery явно развела эти два метода начиная с версии 1.6 и с тех пор рекомендует .prop() для всех булевых состояний — checked, selected, disabled; это верно и для jQuery 3.7, и для 4.0.

Селекторы :checkbox и :input из набора селекторов форм удобны, чтобы отобрать все чекбоксы или вообще все элементы управления формы без перечисления тегов; подробнее про синтаксис селекторов — в статье про селекторы jQuery.

Select: выбор и опции

Значение и видимый текст выбранного пункта — разные вещи и читаются по-разному:

<select id="country">
  <option value="ru">Россия</option>
  <option value="kz" selected>Казахстан</option>
</select>

$("#country").val();                    // "kz"
$("#country option:selected").text();   // "Казахстан"
$("#country").prop("selectedIndex");    // 1

Выбрать пункт программно — та же запись через .val(), которую использовали для текстовых полей:

$("#country").val("ru");

Добавить или очистить список опций:

// Добавить один option
$("#country").append($("<option>", { value: "by", text: "Беларусь" }));

// Полностью очистить список перед перестройкой
$("#country").empty();

Частая задача — зависимые списки: выбор в одном select должен перестроить набор опций в другом (например, страна → город). Схематично, без конкретного API бэкенда:

$("#country").on("change", function () {
  var country = $(this).val();
  var $city = $("#city").empty().prop("disabled", true);

  $.getJSON("/api/cities", { country: country }, function (cities) {
    $.each(cities, function (i, city) {
      $city.append($("<option>", { value: city.id, text: city.name }));
    });
    $city.prop("disabled", false);
  });
});

Пока список городов не загружен, select лучше держать disabled — это защищает от отправки формы с ещё не заполненным полем, а заодно наглядно показывает пользователю, что идёт загрузка.

disabled и readonly

Оба атрибута мешают пользователю менять поле, но по-разному влияют на отправку формы. Управлять обоими нужно через .prop(), как и с checked:

$("#promo-code").prop("disabled", true);
$("#promo-code").prop("readonly", true);
disabledreadonly
Можно менять значениенетнет (для текстовых полей; чекбоксы, radio и select атрибут readonly не поддерживают)
Попадает в .serialize() / отправляется на сервернетда
Селектор для поиска:disabled—
Противоположный селектор:enabled (все поля, у которых нет disabled)—

Практический вывод: если поле должно просто не отправляться на сервер (например, промокод, применённый только для предпросмотра цены на клиенте) — используйте disabled. Если поле должно уйти на сервер как есть, но пользователь не должен его редактировать (например, e-mail, подставленный из профиля) — readonly.

Сбор данных формы

Для обычных полей (без файлов) есть два готовых метода. .serialize() сразу даёт строку в формате application/x-www-form-urlencoded, как если бы форму отправили без Ajax:

$("#order-form").on("submit", function (event) {
  event.preventDefault();
  var data = $(this).serialize();
  // "name=%D0%98%D0%B2%D0%B0%D0%BD&email=ivan%40example.com&topics=news"
  $.post("/order", data);
});

.serializeArray() отдаёт те же данные структурой, с которой удобнее работать в JS — массивом объектов { name, value }:

$("#order-form").serializeArray();
// [ { name: "name", value: "Иван" }, { name: "email", value: "ivan@example.com" } ]

Если нужен обычный объект «ключ → значение», собрать его из serializeArray() — пара строк:

function formToObject($form) {
  var data = {};
  $.each($form.serializeArray(), function (i, field) {
    data[field.name] = field.value;
  });
  return data;
}

Оба метода учитывают только «успешные элементы управления» формы и молча пропускают часть полей — это не баг, а спецификация HTML-форм:

  • поля без атрибута name — попадают в вывод только по имени, без имени сериализовать нечего;
  • disabled-поля — исключены полностью (см. раздел выше);
  • неотмеченные чекбоксы и radio — не отправляются вообще (в отличие от, например, false для булева поля — если чекбокс не отмечен, ключа не будет в данных вовсе);
  • кнопки (<button>, <input type="submit">) — .serialize() не включает их никогда: jQuery не знает, какой кнопкой отправили форму. Если имя/значение кнопки важно серверу, добавьте его в данные вручную или используйте new FormData(form, event.originalEvent.submitter);
  • <input type="file"> — содержимое файлов оба метода не передают вообще, независимо от того, выбран файл или нет.

Для файлов нужен FormData — нативный браузерный объект, который умеет собрать данные формы, включая файлы, напрямую из DOM-элемента:

$("#upload-form").on("submit", function (event) {
  event.preventDefault();
  var formData = new FormData(this); // this — DOM-элемент, не jQuery-объект

  $.ajax({
    url: "/upload",
    method: "POST",
    data: formData,
    processData: false, // не превращать FormData в строку
    contentType: false,  // Content-Type (с boundary) браузер выставит сам
    success: function () {
      console.log("файл загружен");
    }
  });
});

Два флага, processData: false и contentType: false, обязательны: без них $.ajax попытается сериализовать FormData как обычный объект и потеряет файлы. Подробнее про параметры $.ajax, обработку ответа и ошибок — в статье про Ajax в jQuery.

Валидация

Первый слой проверки — встроенный в браузер, без единой строчки JS. Атрибуты required, pattern, type="email"/"number"/"url", min/max, minlength/maxlength браузер проверяет сам при попытке отправить форму и показывает нативную подсказку около поля:

<form id="signup-form">
  <input type="email" name="email" required>
  <input type="tel" name="phone" pattern="\+7\d{10}" required>
  <button type="submit">Отправить</button>
</form>

Тот же механизм доступен из кода через Constraint Validation API — checkValidity() просто возвращает true/false, а reportValidity() ещё и показывает браузерную подсказку у невалидного поля, как при обычной отправке. Оба метода — нативные, вызываются на DOM-элементе, а не на jQuery-объекте:

$("#signup-form").on("submit", function (event) {
  if (!this.checkValidity()) {
    event.preventDefault();
    this.reportValidity(); // подсветит проблемные поля стандартной подсказкой браузера
  }
});

Для точечных сообщений об ошибке (например, «такой e-mail уже зарегистрирован» — то, что браузер сам знать не может) есть setCustomValidity(): пока строка не пустая, поле считается невалидным.

var $email = $("#email");
$email.on("input", function () {
  this.setCustomValidity(""); // сбросить кастомную ошибку при каждом вводе
});

// где-то после ответа сервера, что e-mail занят:
$email[0].setCustomValidity("Этот e-mail уже зарегистрирован");
$email[0].reportValidity();

Своя проверка на submit нужна, когда логика сложнее, чем поддерживают HTML5-атрибуты (сравнить два поля, проверить сумму, обратиться к данным на странице):

$("#order-form").on("submit", function (event) {
  var $pass = $("#password");
  var $confirm = $("#password-confirm");

  if ($pass.val() !== $confirm.val()) {
    event.preventDefault();
    $confirm.addClass("field-error");
    return;
  }
  $confirm.removeClass("field-error");
});

Если проверок много и нужны стандартные вещи — обязательные поля, e-mail, числовые диапазоны, показ ошибок рядом с полем — есть смысл не писать всё руками, а взять плагин jQuery Validation. Поддержка jQuery 4.0.0 добавлена в версии плагина 1.22.0 (это отмечено в списке изменений релиза), так что для проектов на jQuery 4 берите 1.22.x или новее.

$("#order-form").validate({
  rules: {
    email: { required: true, email: true },
    phone: { required: true, minlength: 10 }
  },
  messages: {
    email: "Введите корректный e-mail",
    phone: "Укажите телефон для связи"
  },
  errorElement: "span",
  errorPlacement: function (error, element) {
    error.addClass("field-error").insertAfter(element);
  }
});

По умолчанию плагин сам решает, когда проверять поле повторно после первой неудачной попытки (обычно — по мере ввода), но общую схему «живой» проверки легко сделать и без плагина: слушать focusout для первой проверки после того, как пользователь ушёл с поля, и input — для повторной проверки уже отмеченных как ошибочные полей:

$("#email").on("focusout", function () {
  $(this).toggleClass("field-error", !this.checkValidity());
});
$("#email").on("input", function () {
  if ($(this).hasClass("field-error")) {
    $(this).toggleClass("field-error", !this.checkValidity());
  }
});

Клиентская валидация — это только удобство для пользователя, а не защита. Любую проверку, которая есть в браузере или в плагине, нужно повторить и на сервере: атрибуты required/pattern легко обойти прямым запросом к API, минуя форму и JS вовсе.

Маски ввода

Для номеров телефона и подобных полей с фиксированным форматом есть два уровня решения. Самый простой — не маска, а подсказка браузеру и мобильной клавиатуре через атрибуты, без единой строчки JS:

<input type="tel" name="phone" inputmode="numeric" pattern="\+7\d{10}" placeholder="+79991234567">

inputmode="numeric" переключает клавиатуру на телефоне на цифровую, pattern подключает нативную проверку формата при отправке — но сам ввод при этом не форматируется на лету (никаких скобок и дефисов, которые расставляются автоматически).

Если нужна визуальная маска — автоподстановка скобок, дефисов, дефолтного +7 по мере ввода — потребуется плагин. Здесь важен выбор: старый и когда-то популярный jquery.maskedinput давно не обновляется, и для новых проектов его лучше не брать. Из поддерживаемых вариантов чаще всего используют Inputmask — он работает и как самостоятельная библиотека, и как jQuery-плагин. Конкретный синтаксис масок и способ подключения зависят от версии плагина, поэтому берите их из документации той версии, которую ставите, а не из старых примеров в интернете.

Прежде чем добавлять плагин маски в проект, стоит свериться с его статусом на GitHub — дата последнего релиза, совместимость с вашей версией jQuery, открытые критичные issue. И помните, что маска — только удобство ввода: формат всё равно проверяется на сервере.

Отправка формы

Отправка без перезагрузки страницы — это submit формы плюс $.ajax или его сокращённый вариант $.post:

$("#order-form").on("submit", function (event) {
  event.preventDefault();
  var $form = $(this);

  $.post($form.attr("action"), $form.serialize())
    .done(function () {
      console.log("заказ отправлен");
    })
    .fail(function () {
      console.log("ошибка отправки");
    });
});

event.preventDefault() здесь обязателен — без него браузер продолжит обычную отправку формы (переход по action) параллельно с Ajax-запросом. Разбор параметров $.ajax/$.post, обработки ответа и ошибок — в статье про Ajax в jQuery; про то, как вообще устроены обработчики событий вроде submit и делегирование — в статье про события в jQuery.

Защита от повторной отправки при двойном клике или медленном ответе сервера — заблокировать кнопку сразу после первого submit:

$("#order-form").on("submit", function () {
  $(this).find("button[type=submit]").prop("disabled", true).text("Отправляем…");
});

Кнопка становится disabled сразу, ещё до ответа сервера, поэтому повторное нажатие в момент ожидания физически невозможно — в отличие от проверки «уже отправляется» через отдельный флаг в JS, который легко забыть сбросить в одной из веток кода.

Частые ошибки

ОшибкаЧто происходитКак избежать
.attr("checked") вместо .prop("checked")Возвращается исходный HTML-атрибут (defaultChecked), а не текущее состояние после кликаДля checked/selected/disabled — всегда .prop()
Ожидание, что .val("x") сам вызовет changeОбработчики, подписанные на change (свои или сторонних плагинов), не срабатываютПосле программной установки — .trigger("change")
Надежда, что disabled-поле уедет на серверПоле молча пропадает из .serialize()/.serializeArray()Для «неотправляемого, но видимого» значения — disabled; для «отправляемого, но нередактируемого» — readonly
Попытка передать файлы через .serialize()Содержимое <input type="file"> в данные не попадает вовсеFormData + processData: false, contentType: false в $.ajax
Только клиентская валидация (HTML5-атрибуты или плагин)Проверка легко обходится прямым запросом к серверу, минуя формуДублировать все проверки на бэкенде
.val() на группе radio без :checkedВозвращается значение первого radio в DOM, а не отмеченного$("input[name=x]:checked").val()

Чек-лист

  • Значение поля — .val(); состояние (checked/selected/disabled) — .prop(), никогда .attr() для этих трёх.
  • Программная установка .val()/.prop("checked") не порождает change — вызывайте .trigger("change"), если на это событие что-то подписано.
  • Значение отмеченного radio — только через :checked в селекторе, а не .val() на всей группе.
  • Обычные поля — .serialize()/.serializeArray(); файлы — только FormData с processData: false, contentType: false.
  • disabled-поля, неотмеченные чекбоксы, поля без name и файлы в .serialize() не попадают — это ожидаемое поведение, а не баг.
  • Проверка начинается с HTML5-атрибутов (required, pattern, type) и checkValidity()/reportValidity(); сложные правила и готовая разметка ошибок — jQuery Validation (совместим с jQuery 4.0 с версии 1.22.0).
  • Любая клиентская проверка дублируется на сервере — она не защита, а удобство.
  • Плагины визуальных масок — только актуально поддерживаемые; jquery.maskedinput давно не обновляется.
  • Кнопку отправки — disabled сразу в обработчике submit, до ответа сервера, а не по отдельному флагу «уже отправляется».

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

Как получить значение поля ввода в jQuery?

Через .val() без аргументов: $("#email").val() вернёт текущее содержимое текстового поля, textarea или значение выбранного option в select. Для чекбоксов и radio .val() возвращает значение атрибута value независимо от того, отмечен элемент или нет — состояние отметки проверяется отдельно, через .prop("checked").

Как проверить, отмечен ли чекбокс?

Два равнозначных способа: $("#agree").prop("checked") вернёт true/false, либо $("#agree").is(":checked") — то же самое через селектор, удобно прямо в условии if. Устаревший вариант $("#agree").attr("checked") использовать не стоит: атрибут отражает исходную HTML-разметку (defaultChecked), а не текущее состояние после клика пользователя.

Как отметить чекбокс через jQuery?

$("#agree").prop("checked", true) — отметит, false — снимет отметку. Если после этого какой-то код должен среагировать на изменение (например, пересчитать сумму заказа по слушателю change), событие нужно вызвать вручную: .prop("checked", true).trigger("change"), потому что программная установка свойства событие не порождает.

Как получить выбранный option в select?

Значение — $("#country").val(), видимый текст выбранного пункта — $("#country option:selected").text(). Для <select multiple> .val() возвращает массив значений всех выбранных option, а не одно значение; если ничего не выбрано — с jQuery 3.0 это пустой массив, а не null, как было раньше.

Почему .serialize() не видит одно из полей формы?

Самые частые причины: у поля нет атрибута name (serialize берёт данные строго по имени), поле имеет атрибут disabled (такие поля не считаются «успешными элементами управления» и не сериализуются), чекбокс не отмечен, или это <input type="file"> — файлы .serialize() и .serializeArray() не передают вообще, для них нужен FormData.

Как очистить форму в jQuery?

Нативный form.reset() (через DOM-элемент: $("#myform")[0].reset()) возвращает все поля к значениям по умолчанию, заданным в HTML, — так, как это делает кнопка <button type="reset">. Если вместо этого пройтись по полям через .val(""), значения по умолчанию из разметки не восстановятся, а просто станут пустыми — для чекбоксов и select это не то же самое, что «сброс».

Как запретить отправку формы по Enter в текстовом поле?

Если в форме одно текстовое поле, браузер отправляет её по Enter даже без явной кнопки submit — это стандартное поведение HTML-форм (implicit submission), а не особенность jQuery. Отключить его точечно можно, поймав keydown на нужном поле и вызвав event.preventDefault() для клавиши Enter, либо обработав сам submit формы и решая там, продолжать отправку или нет.

[ наверх ]









 




Справочник по jQuery JavaScript API на русском языке