📄 pbForm: Быстрая и надёжная обработка форм
pbForm — это готовый класс для удобной AJAX-валидации и отправки форм на клиенте. Он интегрируется с pbFetch и автоматически обрабатывает ошибки, сообщения и редиректы.
✨ Основные возможности
- Перехватывает отправку форм: предотвращает стандартный submit и отправляет данные через
pbFetchс использованиемFormData. - Обрабатывает ошибки полей: если API возвращает ошибки валидации (например,
{ errors: { email: "Некорректный email" } }), класс добавляет CSS-классы к полям и выводит сообщения. - Показывает, куда смотреть: прокручивает страницу к первому непрошедшему полю и ставит в него фокус.
- Поддерживает кастомные элементы: можно использовать
data-error="name"иdata-custom="name"для гибкой разметки. - Автоочистка ошибок: убирает старые ошибки при повторном вводе или после успешной отправки.
- Блокирует кнопку и показывает спиннер на время запроса.
- Поддержка редиректа: если сервер возвращает
redirect, форма автоматически перенаправит пользователя. - Поддержка reCAPTCHA v3: токен запрашивается сам, перед самой отправкой.
- Настройка CSS-классов: классы ошибок и сообщений можно задать через опции конструктора или системные настройки.
⚙️ Как использовать
1️⃣ Добавить атрибут pb-form форме
<form action="/api/register" method="POST" pb-form>
<input name="email">
<span data-error="email"></span>
<button type="submit">Отправить</button>
</form>2️⃣ Инициализировать класс
При включённой системной настройке pageblocks_load_scripts всё запускается автоматически. Если нужно вручную:
<script src="/assets/components/pageblocks/js/web/pb.fetch.v300.js"></script>
<script src="/assets/components/pageblocks/js/web/pb.message.v300.js"></script>
<script src="/assets/components/pageblocks/js/web/pb.form.v300.js"></script>
<script>
pbFetch.init();
new pbForm('form[pb-form]', {
errorClass: 'is-invalid',
errorMessageClass: 'invalid-feedback'
});
</script>Опции:
errorClass: CSS-класс для невалидных полей.errorMessageClass: CSS-класс для блока с сообщением об ошибке.
По умолчанию они берутся из системных настроек:
pageblocks_field_error— класс для поля с ошибкой (по умолчаниюis-invalid).pageblocks_field_msg_error— класс для текста ошибки (по умолчаниюinvalid-feedback).
Пустая настройка не сломает форму
Если настройку очистили, в конструктор приедет пустая строка, а classList.add('') бросает token must not be empty и рушит обработчик целиком. pbForm подставляет на этот случай свои значения по умолчанию.
Обработчики вешаются один раз на document, а не на каждую форму. Поэтому формы, добавленные в DOM позже (пришедшие AJAX-ом, из модалки), работают без повторной инициализации.
3️⃣ Пример реальной формы с Bootstrap 5
<form class="border rounded-4 p-5" action="/login" method="post" pb-form>
<input type="hidden" name="_token" value="{csrf_token}">
<input type="hidden" name="honeypot" value="">
{if $success_message}
<p class="text-center text-success" pb-message>{$success_message}</p>
{elseif $error_message}
<p class="text-center text-danger text-error" pb-message>{$error_message}</p>
{else}
<p class="text-center d-none" pb-message></p>
{/if}
<div class="form-group mb-3">
<label for="username" class="mb-2">Имя</label>
<input type="text"
name="username"
id="username"
class="form-control{if $errors.username} is-invalid{/if}"
value="{$old_input.username}">
<span class="invalid-feedback" data-error="username">{$errors.username}</span>
</div>
<div class="form-group mb-3">
<label for="password" class="mb-2">Пароль</label>
<input type="password"
name="password"
id="password"
class="form-control{if $errors.password} is-invalid{/if}">
<span class="invalid-feedback" data-error="password">{$errors.password}</span>
</div>
<button type="submit" class="btn btn-dark w-100">
<span class="spinner spinner-border spinner-border-sm"
pb-spinner
aria-hidden="true"
style="display:none">
</span>
<span role="status">Войти</span>
</button>
</form>🔍 Особенности примера
- ✅ Используется
<p pb-message>для вывода общего сообщения об успехе или ошибке. - ✅ Для полей ошибок применяется
data-error="name"и CSS-классы, указанные в системных настройках (field_errorиfield_msg_error). - ✅ Кнопка отправки автоматически блокируется на время запроса, а внутри неё отображается спиннер с атрибутом
pb-spinnerдля удобной индикации загрузки.
🎯 Прокрутка к первой ошибке
Длинную форму отправляют с её конца, а не прошло поле в начале — человек видел только «Проверка не пройдена» и не знал, куда смотреть. Поэтому после разбора ответа pbForm берёт первое поле из errors, плавно прокручивает страницу к нему (block: 'center') и ставит фокус.
Порядок полей задаёт сервер: подсвечивается первый ключ объекта errors, а не первое поле в разметке.
Choices работает
Библиотека Choices прячет исходный <select> внутри своего контейнера, и браузер молча отказывается и прокручивать к нему, и ставить фокус. pbForm это учитывает: находит обёртку .choices, прокручивает к ней и фокусирует внутренний input.choices__input.
По той же причине подсветка снимается не только по input, но и по change: выбор в select события input не даёт, и класс ошибки висел на уже исправленном поле до следующей отправки.
🧹 Что происходит после успеха
- Если в ответе есть непустое поле
redirect— переход по адресу, и на этом всё. - Иначе форма очищается через
form.reset(). - Снимаются все классы ошибок и тексты ошибок у полей, а блок общего сообщения очищается и снова прячется.
Общее сообщение чистится в контексте самой формы — так же, как оно туда попадает. Поэтому блок [pb-message] должен лежать внутри формы: снаружи pbForm его не найдёт ни чтобы показать сообщение, ни чтобы убрать.
Очистку можно отключить — например, когда форму заполняют многократно подряд (добавление позиций, поиск):
<form action="/api/items" method="post" pb-form data-noclear>
…
</form>🛡️ reCAPTCHA v3
Достаточно положить в форму скрытое поле — токен pbForm получит сам, в колбэке before, то есть непосредственно перед отправкой (токен живёт две минуты, брать его заранее нельзя):
<form action="/api/feedback" method="post" pb-form data-action="feedback">
<input type="hidden" name="g-recaptcha-response" data-key="{$recaptcha_public_key}">
…
</form>data-key— публичный ключ сайта, из системной настройкиpageblocks_recaptcha_public_key.data-actionна форме — имя действия для reCAPTCHA; по умолчаниюform.
Скрипт Google подключается автоматически, если настройка с публичным ключом заполнена. После завершения запроса значение поля сбрасывается, чтобы повторная отправка не ушла со «сгоревшим» токеном.
🏷️ Разметка ошибок
| Атрибут | Что делает |
|---|---|
data-error="name" | Элемент, куда попадёт текст ошибки поля name; получает errorMessageClass. |
data-custom="name" | Дополнительный элемент, которому вешается errorClass вместе с самим полем. |
pb-spinner | Индикатор внутри кнопки; показывается на время запроса. |
pb-message | Блок общего сообщения формы (см. pbMessage). |
data-custom нужен там, где настоящий <input> скрыт или подменён — файловая загрузка, кастомный чекбокс, тот же Choices. Класс ошибки на невидимом поле пользователю ничего не скажет, поэтому его дублируют на видимую обёртку:
<div class="dropzone" data-custom="photo">
<input type="file" name="photo" class="d-none">
<span>Перетащите файл</span>
</div>
<span class="invalid-feedback" data-error="photo"></span>Класс ошибки вешается на все поля с этим именем — группа чекбоксов name="tags[]" подсветится целиком.
🔧 Индивидуальные формы с другими классами
Можно инициализировать формы с другими селекторами и своими классами ошибок:
new pbForm('.custom-ajax-form', {
errorClass: 'has-error',
errorMessageClass: 'field-error'
});🗂 Системные настройки по умолчанию
| Настройка | Значение по умолчанию | Описание |
|---|---|---|
pageblocks_field_error | is-invalid | Класс для поля с ошибкой |
pageblocks_field_msg_error | invalid-feedback | Класс для блока сообщения об ошибке |
pageblocks_msg_success | text-success | Классы для успешного общего сообщения |
pageblocks_msg_error | text-error,text-danger | Классы для общего сообщения об ошибке |
pageblocks_hidden_class | d-none | Класс для скрытия блока сообщений |
📡 Что ждёт от сервера
Запрос уходит методом POST на form.action с expect: 'json'. Разбираются три поля ответа:
{
"message": "Заявка отправлена",
"redirect": "/thanks",
"errors": {
"email": "Некорректный email",
"phone": ["Телефон обязателен"]
}
}errors— объект «поле → сообщение»; значением может быть строка или массив, в этом случае берётся первый элемент. Читается только при HTTP-статусе ошибки (422и подобные).redirect— куда уйти после успеха.message— общее сообщение, его показываетpbMessage(это делает ужеpbFetch, а не самpbForm).
✅ Итог
pbForm — это простая и гибкая основа для AJAX-форм с авто-валидацией и обработкой ошибок. Добавьте атрибут pb-form, настройте системные параметры и форма будет готова к работе без лишнего JS.