Skip to content

🚀 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

  1. Enable the pageblocks_load_scripts setting for automatic script loading.
  2. Or manually include:
html
<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-target and pb-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

AttributeDescription
pb-getSends a GET request.
pb-postSends a POST request.
pb-putSends a PUT request.
pb-patchSends a PATCH request.
pb-deleteSends a DELETE request.
pb-pathAlternative way to specify a URL.
pb-targetCSS selector of the element where the response will be inserted.
pb-swapInsertion method: innerHTML, beforeend, afterbegin, beforebegin, afterend, outerHTML. Special meanings: active, inactive, delete, hide
pb-expectExpected response format: html (default) or json.
pb-triggerEvents that trigger the request: click, submit, change, load (multiple events can be comma-separated).
pb-valsJSON string with request body data.
pb-includeCSS selector of form fields to include in the request.
pb-indicatorCSS 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.

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

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

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

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

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

html
<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} → the id attribute of the element
  • {name} → the name attribute of the element

Example:

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

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

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

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

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

js
pbFetch.get(options)  
pbFetch.post(options)  
pbFetch.put(options)  
pbFetch.patch(options)  
pbFetch.delete(options)

Examples

js
// 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

OptionDescription
methodHTTP method (GET, POST, PUT, PATCH, DELETE).
urlRequest URL.
targetCSS selector for HTML insertion.
swapInsertion method (innerHTML, beforeend, afterbegin, beforebegin, afterend, outerHTML).
expectResponse format: html or json.
bodyRequest body (e.g., URLSearchParams, FormData, JSON).
headersCustom headers.
formForm element (HTMLFormElement).
showProgressWhether to fire progress:start/end events.
cancelKeyRequest cancellation key (default: URL without query parameters).
cancelPreviousCancel previous requests with the same key.
beforeCallback before request. Returning false cancels the request.
successCallback on successful response.
errorCallback on error.
afterCallback after request completion (always fires).

🗨️ Events

EventTriggered When
pb:beforeBefore sending. Can be canceled.
pb:responseAfter receiving a response, before processing.
pb:successAfter a successful response. Can suppress pbMessage.
pb:errorAfter an error. Can suppress pbMessage.
pb:progress:startWhen loading starts (if showProgress).
pb:progress:endWhen loading ends (if showProgress).
pb:afterAfter request completion (always fires).
pb:abortIf the request is aborted.
pb:failOn network errors (e.g., no server connection).

Example

js
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 load event, 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.

© PageBlocks 2019-present