Skip to content

Out of box HTMX Support for Array Field

Version Information

Introduced at the 0.6.0 version.

Behaviour

The behaviour for the out of box HTMX support for Array Field is a little bit different of the widget. The array field uses the base of inline admin to render the widget and the drag and drop support request initialization. Then to add out of box support, we decided to handle the initialization inside the htmx:afterSwap event:

// image-uploader-inline.js
//
// ...
//
document.addEventListener('DOMContentLoaded', function() {
  initialize();
});
document.addEventListener('htmx:afterSwap', function(ev) {
  initialize(ev.target);
})

Usage example

The usage example is the same of the widget. The parent view and template is created using:

# views.py
def render_parent(request):
    form = TestRequiredForm()
    form2 = TestWithArrayFieldForm()
    context = {
        "media": form.media + form2.media,
    }
    template = "test_htmx.html"
    return render(request, template, context=context)
<!-- test_htmx.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTMX</title>
  {{ media }}
</head>
<body  hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>

  <button
    hx-get="/test-htmx-image-widget/array_field/"
    hx-target="this"
    hx-swap="outerHTML"
    hx-trigger="click"
    type="button"
    class="btn-load"
  >
    Load
  </button>

  <script src="https://unpkg.com/htmx.org@1.9.12"></script>
</body>
</html>

The widget view and template is created using:

# views.py
def render_array_field_required(request, pk=None):
    instance = TestWithArrayField.objects.get(pk=pk) if pk else None
    if request.method == "POST":
        form = TestWithArrayFieldForm(
            instance=instance, data=request.POST, files=request.FILES
        )
        if form.is_valid():
            form.save()
            instance = form.instance
            form = TestWithArrayFieldForm(instance=instance)
            add_message(request, SUCCESS, "Saved")
    else:
        form = TestWithArrayFieldForm(instance=instance)

    context = {
        "form": form,
        "instance": instance,
        "post_url": "test-htmx-image-widget/array_field",
    }
    template = "test_htmx_widget.html"
    return render(request, template, context=context)
<!-- test_htmx_widget.html -->
<form
  hx-post="/test-htmx-image-widget/array_field/{% if instance %}{{ instance.pk }}/{% endif %}"
  hx-target="this"
  hx-swap="outerHTML"
  enctype="multipart/form-data"
  id="my-widget-form"
>
  {% if messages %}
    <ul class="messagelist">
      {% for message in messages %}
        <li class="{{ message.tags }}">{{ message }}</li>
      {% endfor %}
    </ul>
  {% endif %}

  {{ form }}

  <button class="btn-submit" type="submit">Submit</button>
</form>