Skip to content

📄 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 форме

html
<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 всё запускается автоматически. Если нужно вручную:

html
<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

html
<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 не даёт, и класс ошибки висел на уже исправленном поле до следующей отправки.

🧹 Что происходит после успеха

  1. Если в ответе есть непустое поле redirect — переход по адресу, и на этом всё.
  2. Иначе форма очищается через form.reset().
  3. Снимаются все классы ошибок и тексты ошибок у полей, а блок общего сообщения очищается и снова прячется.

Общее сообщение чистится в контексте самой формы — так же, как оно туда попадает. Поэтому блок [pb-message] должен лежать внутри формы: снаружи pbForm его не найдёт ни чтобы показать сообщение, ни чтобы убрать.

Очистку можно отключить — например, когда форму заполняют многократно подряд (добавление позиций, поиск):

html
<form action="/api/items" method="post" pb-form data-noclear>

</form>

🛡️ reCAPTCHA v3

Достаточно положить в форму скрытое поле — токен pbForm получит сам, в колбэке before, то есть непосредственно перед отправкой (токен живёт две минуты, брать его заранее нельзя):

html
<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. Класс ошибки на невидимом поле пользователю ничего не скажет, поэтому его дублируют на видимую обёртку:

html
<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[]" подсветится целиком.

🔧 Индивидуальные формы с другими классами

Можно инициализировать формы с другими селекторами и своими классами ошибок:

javascript
new pbForm('.custom-ajax-form', {
  errorClass: 'has-error',
  errorMessageClass: 'field-error'
});

🗂 Системные настройки по умолчанию

НастройкаЗначение по умолчаниюОписание
pageblocks_field_erroris-invalidКласс для поля с ошибкой
pageblocks_field_msg_errorinvalid-feedbackКласс для блока сообщения об ошибке
pageblocks_msg_successtext-successКлассы для успешного общего сообщения
pageblocks_msg_errortext-error,text-dangerКлассы для общего сообщения об ошибке
pageblocks_hidden_classd-noneКласс для скрытия блока сообщений

📡 Что ждёт от сервера

Запрос уходит методом POST на form.action с expect: 'json'. Разбираются три поля ответа:

json
{
  "message": "Заявка отправлена",
  "redirect": "/thanks",
  "errors": {
    "email": "Некорректный email",
    "phone": ["Телефон обязателен"]
  }
}
  • errors — объект «поле → сообщение»; значением может быть строка или массив, в этом случае берётся первый элемент. Читается только при HTTP-статусе ошибки (422 и подобные).
  • redirect — куда уйти после успеха.
  • message — общее сообщение, его показывает pbMessage (это делает уже pbFetch, а не сам pbForm).

✅ Итог

pbForm — это простая и гибкая основа для AJAX-форм с авто-валидацией и обработкой ошибок. Добавьте атрибут pb-form, настройте системные параметры и форма будет готова к работе без лишнего JS.

© PageBlocks 2019-present