Issue
The other day someone suggested me to start using the django_htmx module to boost my htmx experience in the framework. One of the functionalities I'm more interested on is the trigger_client_event response modifier that seems to be able to trigger an event in the client.
Here's the code I'm using in the back-end and the client:
[customMixins.py]
from django.views import View
from django_htmx.http import retarget, reswap, trigger_client_event
class HxFormValidationMixin(View):
hx_retarget = 'this'
hx_reswap = 'innerHTML'
hx_event = ''
def form_invalid(self, form):
response = super().form_invalid(form)
return reswap(retarget(response, self.hx_retarget), self.hx_reswap)
def form_valid(self, form):
response = super().form_valid(form)
return trigger_client_event(response, self.hx_event)
[views.py]
...
class AAList(ListView):
model = AssistantStudent
template_name = 'AA/AlumnosAyudanteList.html'
queryset = AssistantStudent.objects.all().order_by('as_group','as_name')
#def dispatch(self, request, *args, **kwargs):
# response = super().dispatch(request, *args, **kwargs)
# return trigger_client_event(response, 'modalHide')
class AAUpdate(HxFormValidationMixin, UpdateView):
template_name = 'AA/AlumnoAyudanteForm.html'
model = AssistantStudent
form_class = AssistantStudentForm
success_url = reverse_lazy('list-alumnos-ayudante')
hx_retarget = '#AAForm'
hx_event = 'modalHide'
...
[script.js]
...
$(document).on('modalHide', function(event) {
$('#assistantStudentModal').modal('hide');
});
...
[AlumnosAyudante.html]
...
<table id="AAList" hx-trigger="load" hx-get="{% url 'list-alumnos-ayudante' %}" hx-target="this">
<tr>
<td colspan="5">
<div class="d-flex justify-content-center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</td>
<td></td>
</tr>
</table>
<div class="modal fade" id="assistantStudentModal" tabindex="-1" aria-labelledby="assistantStudentModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" id="AAForm">
{% include 'AA/AlumnoAyudanteForm.html' %}
</div>
</div>
</div>
...
[AlumnoAyudanteForm.html]
<div class="modal-header">
<h5 class="modal-title" id="assistantStudentModalLabel">{% if object %}Editar{% else %}Crear{% endif %} Alumno Ayudante</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form hx-post="{{targetURL}}" hx-target="#AAList" method="POST">
{% csrf_token %}
{{form.as_div}}
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
<button type="submit" class="btn btn-primary">Guardar</button>
</div>
</form>
</div>
When the commented code in the views is un-commented the event is processed adequately. But this is just a patch since the 'modalHiden' event should trigger when the form is posted and validated.
I made a lot of debugging and checked that the pipeline is working correctly. The client is receiving the expected Hx-Trigger:{'modalHide':{}}
header in the response to the form submitted POST-REQUEST. Yet the event is not being triggered. The only difference between the two cases (code commented and un-commented) is that one is a POST-REQUEST and the other is a GET-REQUEST.
HERE are pictures of the browser dev tools where you can see the headers of the POST-REQUEST and subsequent GET-REQUEST when the code is un-commented. Only the second case triggers the event.
Where lays the problem?
Solution
The reason for this behaviour is once the redirection is done, all htmx specific headers are cleared (they are not passed to another request), hence the htmx cannot process the response. It's "taken over" by the browser, which handles it as a normal django response.
When using response = super().form_valid(form)
, it cause django to trigger redirect internally, due to how UpdateView
works.
You need to return an html response, so instead of:
response = super().form_valid(form)
return trigger_client_event(response, self.hx_event)
you need to do:
response = render(
self.request,
"your_template.html",
self.get_context_data(),
)
return trigger_client_event(response, self.hx_event)
HTMX will inject the rendered html in whatever target you've set for hx-post.
This shows why CBVs are a bad idea when using htmx, with FBVs it is more readable, you avoid all this overriding and it's easier to control the request/response flow.
Answered By - mariodev
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.