PAD + htmx 🛒 0

How PAD answers htmx

htmx asks for HTML and swaps it in. A PAD page is HTML with names on its parts - so the same template answers the browser's first visit and every question htmx asks after it.

1. Name the part

A {fragment} around the part that changes; the element around it gets the same name as its id:

<input name="q" hx-get="?products" hx-trigger="input changed delay:300ms" hx-target="#results">

<ul id="results">
  {fragment 'results'}
    {products}<li>{$name}</li>{/products}
  {/fragment}
</ul>

2. PAD answers the part alone

htmx sends HX-Request: true and the id of the element it swaps in HX-Target. When the page has a fragment of that name, the answer is that fragment and nothing else - no wrapper, no rest of the page; when it has none the page renders whole, as it always did. A request can also name the fragment itself, for an element without an id or another part than the target:

<tr hx-get="?orders&p=2&padFragment=rows" hx-trigger="revealed" hx-swap="afterend">

The page's PHP runs as for any request - $q is the request's value - and may narrow what the fragment shows: $padFragmentOnly = 'row' sets the answer from PHP. A fragment inside a loop answers with the first row it renders, so narrow the rows to the one asked for.

3. Posts carry the token

With $padCsrf on, a post without the session's token is refused before the page runs. A {form} carries it as a field; for an hx-post on anything else, put the header on the body once - the ^ sigil writes the array as JSON for the attribute:

<body hx-headers="{^headers}">          <!-- $headers = [ 'X-CSRF-Token' => padCsrfToken () ] -->

4. Forms check the same rules twice

Fields with rules= are checked on the server before the PHP runs, and with client in the browser first. Posted through htmx, a form that broke a rule comes back as its own fragment, refilled, with PAD's messages beside the fields:

<div id="signup">{fragment 'signup'}
  {form 'signup', client, error, hx-post='?signup', hx-target='#signup'}
    {input 'email', label='E-mail', rules='required|email'}
  {/form}
{/fragment}</div>

5. More than one place

An answer can update other parts of the page as well: elements in it marked hx-swap-oob="true" go where their id is - the cart count in the header, a summary beside the list.

6. Pushed by the server

padSse() keeps a page's connection open and sends events; with htmx's sse extension each event's HTML is swapped in as it arrives:

<div hx-ext="sse" sse-connect="?ticker" sse-close="done">
  <ol sse-swap="tick" hx-swap="afterbegin"></ol>
</div>

The page cache knows htmx: a request for a part is answered fresh and never stored, and a fragment chosen by a header is never stored under the page's address.