🚀 pbFetch: асинхронные запросы через HTML-атрибуты
pbFetch — это нативный JavaScript-класс для работы с AJAX-запросами, вдохновлённый подходом HTMX, но с собственным неймспейсом pb-. Реализует отправку GET, POST, PUT, PATCH и DELETE-запросов без перезагрузки страницы и позволяет динамически обновлять контент через декларативные атрибуты.
🔗 Подключение
- Включите настройку
pageblocks_load_scripts, чтобы скрипт подключился автоматически. - Или подключите вручную:
<script src="/assets/components/pageblocks/js/web/pb.fetch.v280.js"></script>
<script>
pbFetch.init();
</script>⚡️ Основные возможности
- Асинхронная загрузка HTML или JSON-ответов.
- Обновление контента через
pb-targetиpb-swap. - Автоматический показ сообщений через
pbMessage. - Поддержка индикаторов загрузки.
- Обработка событий каждого этапа.
- Поддержка множественных событий в
pb-trigger. - Поддержка автоматической загрузки при
pb-trigger="load".
🗂️ Базовые атрибуты
| Атрибут | Описание |
|---|---|
pb-get | Отправка GET-запроса. |
pb-post | Отправка POST-запроса. |
pb-put | Отправка PUT-запроса. |
pb-patch | Отправка PATCH-запроса. |
pb-delete | Отправка DELETE-запроса. |
pb-path | Альтернативный способ указания URL. |
pb-target | CSS-селектор элемента, куда будет вставлен ответ. |
pb-swap | Метод вставки: innerHTML, beforeend, afterbegin, beforebegin, afterend, outerHTML. Особые значения: active, inactive, delete, hide |
pb-expect | Формат ожидаемого ответа: html (по умолчанию) или json. |
pb-trigger | События, которые запускают запрос: click, submit, change, load (можно указать несколько через запятую). |
pb-vals | JSON-строка с данными для тела запроса. |
pb-include | CSS-селектор полей формы, которые нужно включить в запрос. |
pb-indicator | CSS-селектор индикатора загрузки. |
🔸 HTML (pb-expect="html")
1. innerHTML (по умолчанию)
Заменяет содержимое целевого элемента.
<div id="box">Старый контент</div>
<button pb-trigger="click"
pb-url="/get/new-content"
pb-target="#box"
pb-expect="html"
pb-swap="innerHTML">
Заменить контент
</button>➡ После запроса внутри #box появится новый HTML, старый будет удалён.
2. outerHTML
Полностью заменяет сам элемент вместе с его тегом.
<div id="box">Контент</div>
<button pb-trigger="click"
pb-url="/get/full-box"
pb-target="#box"
pb-expect="html"
pb-swap="outerHTML">
Заменить элемент
</button>➡ #box будет заменён целиком (вместе с <div>).
3. beforebegin
Вставляет HTML перед элементом.
<div id="item">Пункт</div>
<button pb-trigger="click"
pb-url="/get/row"
pb-target="#item"
pb-expect="html"
pb-swap="beforebegin">
Вставить перед элементом
</button>➡ Новый HTML будет вставлен перед #item, сам #item не изменится.
4. afterend
Вставляет HTML после элемента.
<div id="item">Пункт</div>
<button pb-trigger="click"
pb-url="/get/row"
pb-target="#item"
pb-expect="html"
pb-swap="afterend">
Вставить после элемента
</button>➡ Новый HTML будет вставлен сразу после #item.
5. beforeend
Добавляет HTML в конец содержимого элемента.
<ul id="list">
<li>Пункт 1</li>
</ul>
<button pb-trigger="click"
pb-url="/get/item"
pb-target="#list"
pb-expect="html"
pb-swap="beforeend">
Добавить элемент
</button>➡ Новый элемент добавится в конец списка (<li> после Пункт 1).
6. afterbegin
Добавляет HTML в начало содержимого элемента.
<ul id="list">
<li>Пункт 1</li>
</ul>
<button pb-trigger="click"
pb-url="/get/item"
pb-target="#list"
pb-expect="html"
pb-swap="afterbegin">
Добавить элемент
</button>➡ Новый элемент появится в начале списка, перед Пункт 1.
{ } JSON (pb-expect="json")
Если указано pb-expect="json", то:
- Сервер должен вернуть JSON.
- Данные не вставляются напрямую в DOM (как при
html). - Они могут обрабатываться через
pb-swap.
1. Динамические параметры в URL
В URL можно использовать плейсхолдеры:
{value}→ текущее значение элемента (el.value){id}→ атрибутidэлемента{name}→ атрибутnameэлемента
Пример:
<select id="country"
name="country"
class="form-select"
pb-get="/api/cities/{value}"
pb-trigger="change"
pb-expect="json"
pb-target="#city">
<option value="" selected disabled>Выберите страну</option>
</select>➡ При выборе страны с id=2 отправится запрос /api/cities/2.
2. pb-swap="delete"
Удаляет элемент из DOM после успешного ответа.
<button type="button"
pb-delete="/cargo/{id}"
pb-expect="json"
pb-target="#order-123"
pb-swap="delete"
id="123"
class="btn-control">
Удалить заказ
</button>➡ Отправляется DELETE /cargo/123, при успехе — удаляется #order-123.
3. pb-swap="active"
Добавляет класс active к элементу.
<button type="button"
pb-patch="/user/{id}/activate"
pb-expect="json"
pb-target="#user-123"
pb-swap="active"
id="123">
Активировать
</button>➡ После ответа JSON к #user-123 добавляется класс active.
4. pb-swap="inactive"
Удаляет класс active.
<button type="button"
pb-patch="/user/{id}/deactivate"
pb-expect="json"
pb-target="#user-123"
pb-swap="inactive"
id="123">
Деактивировать
</button>➡ После ответа JSON у #user-123 убирается класс active.
5. pb-swap="hide"
Скрывает элемент (display: none).
<button type="button"
pb-post="/notifications/read/{id}"
pb-expect="json"
pb-target="#notif-55"
pb-swap="hide"
id="55">
Отметить прочитанным
</button>➡ После ответа JSON #notif-55 будет скрыт.
⚙️ Использование в JavaScript
Методы
pbFetch.get(options)
pbFetch.post(options)
pbFetch.put(options)
pbFetch.patch(options)
pbFetch.delete(options)Примеры
// Простой GET-запрос
pbFetch.get({
url: '/news',
target: '#news-block',
swap: 'beforeend'
});
// POST-запрос с телом
pbFetch.post({
url: '/send',
body: new URLSearchParams({ name: 'John' }),
expect: 'json'
});
// PUT-запрос с JSON
pbFetch.put({
url: '/user/5',
body: JSON.stringify({ name: 'Alice' }),
headers: { 'Content-Type': 'application/json' },
expect: 'json'
});
// PATCH-запрос
pbFetch.patch({
url: '/profile',
body: new FormData(document.querySelector('#profile-form')),
success: (res, el) => console.log('Обновлено:', res),
after: () => console.log('Запрос завершён')
});
// DELETE-запрос
pbFetch.delete({
url: '/item/12',
expect: 'json',
success: (res) => alert('Удалено'),
error: (err) => alert('Ошибка удаления')
});
// Отправка формы
const form = document.querySelector('#form');
pbFetch.post({
url: form.action,
form,
expect: 'json'
});
// Отмена предыдущих запросов
pbFetch.get({
url: '/search?q=test',
cancelKey: '/search',
cancelPrevious: true
});Поддерживаемые опции
| Опция | Описание |
|---|---|
method | HTTP-метод (GET, POST, PUT, PATCH, DELETE). |
url | Адрес запроса. |
target | Селектор для вставки HTML. |
swap | Метод вставки (innerHTML, beforeend, и т.п.). |
expect | Формат ответа: html или json. |
body | Тело запроса (например, URLSearchParams, FormData, JSON). |
headers | Кастомные заголовки. |
form | Элемент формы (HTMLFormElement). |
showProgress | Показывать ли события progress:start/end. |
cancelKey | Ключ запроса для отмены. По умолчанию — URL без query-параметров. |
cancelPrevious | Отменить предыдущий запрос с тем же ключом. |
before | Колбэк перед запросом. Возвращаемое false отменяет отправку. |
success | Колбэк при успешном ответе. |
error | Колбэк при ошибке. |
after | Колбэк после завершения запроса (в любом случае). |
🗨️ События
| Событие | Когда срабатывает |
|---|---|
pb:before | До отправки. Можно отменить. |
pb:response | После получения ответа, до его обработки. |
pb:success | После успешного ответа. Можно отменить показ pbMessage. |
pb:error | После ошибки. Можно отменить показ pbMessage. |
pb:progress:start | При старте загрузки (если showProgress). |
pb:progress:end | После завершения загрузки (если showProgress). |
pb:after | После завершения запроса (в любом случае). |
pb:abort | Если запрос отменён. |
pb:fail | При сетевой ошибке (например, нет связи с сервером). |
Пример
document.addEventListener('pb:success', (e) => {
console.log('Успех:', e.detail);
});
document.addEventListener('pb:error', (e) => {
console.log('Ошибка:', e.detail);
e.preventDefault(); // отменить автоматический показ pbMessage
});✅ Автоматический pbMessage
Если expect="json" и сервер возвращает { message: '...' }, pbFetch вызовет pbMessage.success() или pbMessage.error(). Для отмены этого поведения используйте preventDefault() в pb:success или pb:error.
🏆 Преимущества
- Чистый JS-код без зависимостей.
- Простота — работает «из коробки».
- Поддержка загрузки по
load, множественных событий. - Контроль и гибкость через события и JS-интерфейс.
- Поддержка форм, индикаторов и отмены запросов.
🟢 Заключение
pbFetch — лёгкий и мощный способ внедрения асинхронных запросов в PageBlocks. Всё на чистом HTML и JavaScript. Без зависимостей, с полной управляемостью и расширяемостью.