Okayjack (+django-render-blocks
) extends Django and htmx a smidge so they are even more pleasant to use! 🥳
-
Extends htmx by moving all htmx logic to the request markup by default
- Which template or DTL block to use for a response
- How to handle a successful (valid) form submission vs an errorenous (invalid) ones
- Triggering an action after a response is received
-
Extends Django's REST verbs support (adds a body to PATCH etc)
Codewise, Okayjack is:
- Some Django middleware
- A few HttpResponse classes
- A htmx JavaScript extension.
Normal htmx requests - with a bit of Django form error display - look something like this
<form hx-post="/store">
<input id="title" name="title" type="text" {% if form.title.errors %}class="error"{% endif %}>
{% if form.title.errors %}
<div class='error'>{{ form.title.errors }}</div>
{% endif %}
<button type="submit">Submit</button>
</form>
With Okayjack, you can do this.
{% block title_form %}
<form
hx-post="/store"
hx-success-target="h1"
hx-success-swap="outerHTML"
hx-success-block="this-example-file.html:title_success"
hx-error-block="this-example-file.html:title_form">
<input id="title" name="title" type="text" {% if form.title.errors %}class="error"{% endif %}>
{% if form.title.errors %}
<div class='error'>{{ form.title.errors }}</div>
{% endif %}
<button type="submit">Submit</button>
</form>
{% endblock %}
<template>
{% block title_success %}
<h1>{{ title }}</h1>
{% endblock %}
</template>
This example shows the blocks in the same file as the requesting html. The blocks can actually be in any file however.
Given the above HTML, in the corresponding Django view, we now only have to do the following to handle both success and error variations.
def title(request, question_id):
form = TitleForm(request.POST)
if form.is_valid():
form.save()
return HxSuccessResponse(request, {'form': form)
return HxErrorResponse(request, {'form': form})
-
pip install django-render-blocks
-
Add
okayjack
app to Django project
INSTALLED_APPS = [
...
'render_block',
'okayjack',
]
MIDDLEWARE = [
...
'okayjack.middleware.OkayjackMiddleware',
]
-
Import
okayjack.http
in yourviews.py
to use theHttpResponse-like
classes -
Load htmx extension https://htmx.org/attributes/hx-ext/ in template
Supports all htmx response headers https://htmx.org/reference/#response_headers.
You can use a combination of:
- Regular
hx-*
attributes. E.g.hx-target="..."
- Regular
hx-success-*
attributes - used when Django returns aHxSuccessResponse
. E.g.hx-success-target="..."
- Regular
hx-error-*
attributes - used when Django returns aHxErrorResponse
. E.g.hx-error-target="..."
htmx will use the values of hx-*
unless there is a hx-success-*
or hx-error-*
value (for a success or error response respectively).
The *
in hx-success-*
and hx-error-*
attributes can be any of the following.
- location
- push-url
- redirect
- refresh
- replace-url
- swap
- target
- trigger-after-receive
- trigger-after-settle
- trigger-after-swap
- block
trigger-after-receive
isn't a normal htmx attribute. It sets the HX-Trigger
response header. It had to be renamed so it doesn't conflict with hx-trigger
for triggering the request itself 🤷
block
is the path to a template and optional template block to use when generating the HTML response. E.g.
hx-block="base/home.html:welcome_block"
or hx-success-block="base/home.html:new_item"
Blocks are regular Django template blocks. E.g.
{% block welcome_block %}<p>some html here</p>{% endblock }
The main response classes you will use are
HxResponse(request[, context, block=None, swap=None, trigger-after-receive=None, trigger_after_settle=None, trigger_after_swap=None])
Creates a TemplateResponse-like object using django-render-block and htmx header functions. Its main purpose is to make it easy to specify - on the server side - what htmx should do with a response.
Automatically gets the block name from HX-Block
header, or it can be specified as a kwarg. The format of block should be path/to/template.html:block_name
HxResponse(request, { 'form': form })
Supports optional kwargs
HxResponse(request, { 'form': form, trigger-after-receive='do-this-when-response-is-received'})
HxSuccessResponse(request[, context, block=None, swap=None, trigger-after-receive=None, trigger_after_settle=None, trigger_after_swap=None])
Creating a 'success' HxResponse
. The response will use any hx-success-*
attributes specified in the request markup.
HxErrorResponse(request[, context, block=None, swap=None, trigger-after-receive=None, trigger_after_settle=None, trigger_after_swap=None])
Creates an 'error' HxResponse. The response will use any hx-error-*
attributes specified in the request markup.
Some extra response classes for when you don't intend to swap some new HTML into the page.
A HttpResponse
that tells htmx to do nothing
HxDoNothing()
A HttpResponse
that tells htmx to do a client side redirect to the provided URL
HxRedirect(reverse('home'))
A HttpResponse
that tells htmx to refresh the page
HxRefresh()
A HttpResponse
that tells htmx to trigger an event - and do nothing else.
https://htmx.org/headers/hx-trigger/
trigger: the name of the event to trigger. Can also be JSON string, which allows for triggering multiple events and/or passing data for the event
HxTrigger('close-modal')
Creates a TemplateResponse-like
object using django-render-block to render just a block in a template
The format of block is template_path/template_name:block_name
.
BlockResponse('base/home.html:welcome_block')