🚀 pbFetch: Asynchronous Requests via HTML Attributes
pbFetch is a native JavaScript class for handling AJAX requests, inspired by HTMX but with its own namespace pb-.
It enables sending GET, POST, PUT, PATCH, and DELETE requests without page reloads and allows dynamic content updates via declarative attributes.
🔗 Installation
- Enable the
pageblocks_load_scriptssetting for automatic script loading. - Or manually include:
<script src="/assets/components/pageblocks/js/web/pb.fetch.v280.js"></script>
<script>
pbFetch.init();
</script>⚡️ Key Features
- Asynchronous loading of HTML or JSON responses.
- Content updates via
pb-targetandpb-swap. - Automatic message display via
pbMessage. - Loading indicator support.
- Event handling at every stage.
- Support for multiple events in
pb-trigger. - Auto-loading with
pb-trigger="load".
🗂️ Core Attributes
| Attribute | Description |
|---|---|
pb-get | Sends a GET request. |
pb-post | Sends a POST request. |
pb-put | Sends a PUT request. |
pb-patch | Sends a PATCH request. |
pb-delete | Sends a DELETE request. |
pb-path | Alternative way to specify a URL. |
pb-target | CSS selector of the element where the response will be inserted. |
pb-swap | Insertion method: innerHTML, beforeend, afterbegin, beforebegin, afterend, outerHTML. Special meanings: active, inactive, delete, hide |
pb-expect | Expected response format: html (default) or json. |
pb-trigger | Events that trigger the request: click, submit, change, load (multiple events can be comma-separated). |
pb-vals | JSON string with request body data. |
pb-include | CSS selector of form fields to include in the request. |
pb-indicator | CSS selector for a loading indicator. |
Okay, here is the translation of the provided text into English.
🔸 HTML (pb-expect="html")
1. innerHTML (default)
Replaces the content of the target element.
<div id="box">Old content</div>
<button pb-trigger="click"
pb-url="/get/new-content"
pb-target="#box"
pb-expect="html"
pb-swap="innerHTML">
Replace Content
</button>➡ After the request, new HTML will appear inside #box, the old content will be removed.
2. outerHTML
Completely replaces the element itself along with its tag.
<div id="box">Content</div>
<button pb-trigger="click"
pb-url="/get/full-box"
pb-target="#box"
pb-expect="html"
pb-swap="outerHTML">
Replace Element
</button>➡ #box will be replaced entirely (including the <div> tag).
3. beforebegin
Inserts HTML before the element.
<div id="item">Item</div>
<button pb-trigger="click"
pb-url="/get/row"
pb-target="#item"
pb-expect="html"
pb-swap="beforebegin">
Insert Before Element
</button>➡ New HTML will be inserted before #item, #item itself remains unchanged.
4. afterend
Inserts HTML after the element.
<div id="item">Item</div>
<button pb-trigger="click"
pb-url="/get/row"
pb-target="#item"
pb-expect="html"
pb-swap="afterend">
Insert After Element
</button>➡ New HTML will be inserted immediately after #item.
5. beforeend
Appends HTML to the end of the element's content.
<ul id="list">
<li>Item 1</li>
</ul>
<button pb-trigger="click"
pb-url="/get/item"
pb-target="#list"
pb-expect="html"
pb-swap="beforeend">
Add Item
</button>➡ A new item will be added to the end of the list (<li> after Item 1).
6. afterbegin
Prepends HTML to the beginning of the element's content.
<ul id="list">
<li>Item 1</li>
</ul>
<button pb-trigger="click"
pb-url="/get/item"
pb-target="#list"
pb-expect="html"
pb-swap="afterbegin">
Add Item
</button>➡ A new item will appear at the beginning of the list, before Item 1.
{ } JSON (pb-expect="json")
If pb-expect="json" is specified, then:
- The server must return JSON.
- Data is not inserted directly into the DOM (as with
html). - It can be processed via
pb-swap.
1. Dynamic Parameters in URL
Placeholders can be used in the URL:
{value}→ the current value of the element (el.value){id}→ theidattribute of the element{name}→ thenameattribute of the element
Example:
<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>Select Country</option>
</select>➡ When a country with id=2 is selected, a request will be sent to /api/cities/2.
2. pb-swap="delete"
Removes the element from the DOM after a successful response.
<button type="button"
pb-delete="/cargo/{id}"
pb-expect="json"
pb-target="#order-123"
pb-swap="delete"
id="123"
class="btn-control">
Delete Order
</button>➡ Sends a DELETE /cargo/123 request, on success — removes #order-123.
3. pb-swap="active"
Adds the active class to the element.
<button type="button"
pb-patch="/user/{id}/activate"
pb-expect="json"
pb-target="#user-123"
pb-swap="active"
id="123">
Activate
</button>➡ After the JSON response, the active class is added to #user-123.
4. pb-swap="inactive"
Removes the active class.
<button type="button"
pb-patch="/user/{id}/deactivate"
pb-expect="json"
pb-target="#user-123"
pb-swap="inactive"
id="123">
Deactivate
</button>➡ After the JSON response, the active class is removed from #user-123.
5. pb-swap="hide"
Hides the element (display: none).
<button type="button"
pb-post="/notifications/read/{id}"
pb-expect="json"
pb-target="#notif-55"
pb-swap="hide"
id="55">
Mark as Read
</button>➡ After the JSON response, #notif-55 will be hidden.
⚙️ JavaScript API
Methods
pbFetch.get(options)
pbFetch.post(options)
pbFetch.put(options)
pbFetch.patch(options)
pbFetch.delete(options)Examples
// Simple GET request
pbFetch.get({
url: '/news',
target: '#news-block',
swap: 'beforeend'
});
// POST request with body
pbFetch.post({
url: '/send',
body: new URLSearchParams({ name: 'John' }),
expect: 'json'
});
// PUT request with JSON
pbFetch.put({
url: '/user/5',
body: JSON.stringify({ name: 'Alice' }),
headers: { 'Content-Type': 'application/json' },
expect: 'json'
});
// PATCH request
pbFetch.patch({
url: '/profile',
body: new FormData(document.querySelector('#profile-form')),
success: (res, el) => console.log('Updated:', res),
after: () => console.log('Request completed')
});
// DELETE request
pbFetch.delete({
url: '/item/12',
expect: 'json',
success: (res) => alert('Deleted'),
error: (err) => alert('Deletion failed')
});
// Form submission
const form = document.querySelector('#form');
pbFetch.post({
url: form.action,
form,
expect: 'json'
});
// Cancel previous requests
pbFetch.get({
url: '/search?q=test',
cancelKey: '/search',
cancelPrevious: true
});Supported Options
| Option | Description |
|---|---|
method | HTTP method (GET, POST, PUT, PATCH, DELETE). |
url | Request URL. |
target | CSS selector for HTML insertion. |
swap | Insertion method (innerHTML, beforeend, afterbegin, beforebegin, afterend, outerHTML). |
expect | Response format: html or json. |
body | Request body (e.g., URLSearchParams, FormData, JSON). |
headers | Custom headers. |
form | Form element (HTMLFormElement). |
showProgress | Whether to fire progress:start/end events. |
cancelKey | Request cancellation key (default: URL without query parameters). |
cancelPrevious | Cancel previous requests with the same key. |
before | Callback before request. Returning false cancels the request. |
success | Callback on successful response. |
error | Callback on error. |
after | Callback after request completion (always fires). |
🗨️ Events
| Event | Triggered When |
|---|---|
pb:before | Before sending. Can be canceled. |
pb:response | After receiving a response, before processing. |
pb:success | After a successful response. Can suppress pbMessage. |
pb:error | After an error. Can suppress pbMessage. |
pb:progress:start | When loading starts (if showProgress). |
pb:progress:end | When loading ends (if showProgress). |
pb:after | After request completion (always fires). |
pb:abort | If the request is aborted. |
pb:fail | On network errors (e.g., no server connection). |
Example
document.addEventListener('pb:success', (e) => {
console.log('Success:', e.detail);
});
document.addEventListener('pb:error', (e) => {
console.log('Error:', e.detail);
e.preventDefault(); // suppress automatic pbMessage display
});✅ Automatic pbMessage
If expect="json" and the server returns { message: '...' }, pbFetch will call pbMessage.success() or pbMessage.error().
To disable this, use preventDefault() in pb:success or pb:error.
🏆 Advantages
- Pure JavaScript with no dependencies.
- Works out of the box.
- Supports
loadevent, multiple triggers. - Full control via events and JS API.
- Form support, loading indicators, and request cancellation.
🟢 Conclusion
pbFetch is a lightweight yet powerful way to integrate async requests into PageBlocks. Pure HTML and JavaScript—no dependencies, full control, and extensibility.