htmx: hx-target: swap html vs full page reload
Asked Answered
E

5

6

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?

Eliott answered 4/1, 2021 at 20:53 Comment(2)
If a user submits a form, then only the current form should get submitted (not the other forms of the page). This is standard HTML behaviour. I did once 500 forms on a page ;-) each line one user to be accepted or declined - each line one form.Collector
you can do this by returning a meta tag: https://mcmap.net/q/971356/-how-to-implement-a-redirect-with-htmxChemise
E
15

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
Eliott answered 4/1, 2021 at 20:59 Comment(5)
A full example how to use that would be helpfull, so for example what do I need at the frontent to get that working. Many thanksLigure
@Ligure you don't need much at the frontend. You just need to trigger a htmx event (for example hx-get and return the hx-redirect header, and the whole page reloads. But it is important that the http response containing the hx-redirect is a 200 (not 302).Eliott
ok many thanks, now I understood ..Ligure
It worked for me locally (django) but not in production. Then the full page is loaded in the area of the form, check my updateLigure
@Ligure I saw that you wanted to edit the question. I rejected. Please ask a new question, instead of changing this question.Eliott
R
7

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

Rubinstein answered 26/10, 2021 at 1:53 Comment(0)
P
3

Setting headers to the response is very hacky way of doing things and I would avoid at all costs. Lots of times you would not have access to the request from the code which generates the response.

Besides dealing with headers kind of defeats the whole purpose of why people are switching to HTMX on the first place, which is mainly to make things more transparent and easy to use.

Because HTMX is working with real HTML fragments doing full redirect is actually easier than many people realize.

What I usually do is return a redirect script, like this:

<script>window.location.href="http://test.com/next-page"</script>

Works like a charm, and is also easy to test in your unit tests, if the fragment is in the output or not.

Parol answered 25/3, 2023 at 5:49 Comment(1)
Thank you for this answer. I agree, it is easier if you don't need to read or set http headers. I will use your solution the next time I want to trigger a full-page reload in an htmx based application.Eliott
D
2

In addition to the accepted answers, if using django, this is supported by django-htmx:

from django_htmx.http import HttpResponseClientRedirect

def your_view(request):
    # ...
    return HttpResponseClientRedirect(reverse("where-to-redirect"))
Disappear answered 22/2, 2023 at 14:49 Comment(0)
H
0

After I was not very satisfied with the solution found for one of my projects I turned my attention to full page reload instead of html swap. HX-Redirect is mentioned on htmx.org and other sources, but without clear examples. After some searching, I finally found the perfect solution on reddit:

the more htmx-ish way would be to issue the request via ajax rather than doing a redirect:

<input type="date" name="birthday" hx-get="" hx-target="body"/>

In my project, instead of:

<select id="select-settings" name="select-settings" hx-get="/get-settings" hx-target="#title">
    <option value="">-- Select Settings --</option>
    <option value="super-opt10ns">Dolor qui voluptatem</option>
</select>

I came to:

<select id="select-settings" name="select-settings" hx-get="" hx-target="body">
    <option value="">-- Select Settings --</option>
    <option value="super-opt10ns">Dolor qui voluptatem</option>
</select>

I mention that without needing an end-point with this solution, but still having access to the $_GET variable, you can, for example, update the values ​​of some input fields, or do anything else you need.

Housemaster answered 11/7 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.