htmx: hx-target: swap html vs full page reload

Viewed 2702

I have a page containing several forms.

If a user submits a form, then only the current form should get submitted (not the other forms of the page).

On the server the form gets validated.

Case 1: If validation failed, then the server sends html to the client and the particular form should get swapped and the new form should be added to the DOM. This new form contains an error message. The user can now fix his mistake an submit the form again.

Case 2: The form validation was successful, the data got saved. Now I want to trigger a full-page redirect on the client.

I read the docs of htmx hx-target. I managed to get case-1 working (I like this feature of htmx).

But how can the server trigger a full-page redirect?

2 Answers

I found this:

you can use the HX-Redirect http response header to trigger a redirect on the client.

I create this class for my Django based application. This way a snippet can trigger a reload of the whole page:


class HTTPResponseHXRedirect(HttpResponseRedirect):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self['HX-Redirect']=self['Location']
    status_code = 200

@Tomk, here is an example that should give you a good idea of how to use @guettli's solution. This is an edited snippet from a project that manages events.

views.py

from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.contrib import messages
from django.shortcuts import get_object_or_404
from .models import Event

class HTTPResponseHXRedirect(HttpResponseRedirect):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self["HX-Redirect"] = self["Location"]

    status_code = 200

@login_required
def delete_event(request, event_id: int):

    event = get_object_or_404(Event, pk=event_id)

    if request.method == "DELETE":
        event.delete()
        messages.add_message(request, messages.SUCCESS, "Successfully deleted event!")

    return HTTPResponseHXRedirect(redirect_to=reverse_lazy("events"))

urls.py

from django.urls import reverse_lazy

urlpatterns = [
    path("events", views.list_events, name="events"),
    path(
        "events/delete/<int:event_id>", views.delete_event, name="delete_event"
    )
]

edit_event.html

...
<span hx-delete="{% url 'delete_event' event.id %}" 
      hx-confirm="Are you sure you want to delete this event?" 
      hx-swap="none" 
      class="btn btn-danger fa fa-trash">
</span>
...

Using this approach will allow you to use htmx but also have django redirect the frontend. If you were to do this without htmx you would typically use the django redirect function.

Related