HTMX Django not activating on form fields

I have a form with 3 select options, when the user selects the first one i updated the second with htmx, when the used selects the second i would like to update the third the same way. However, the third doesn't initialize the htmx request.

Here is my django form:


    purchased_by = forms.ModelChoiceField(
        label="Empresa compradora",
        queryset=OurCompany.objects.filter(definecat=2).order_by('name'),
        widget=forms.Select(attrs={'class': 'form-control',
                                   'hx-get': reverse_lazy('compras:oc_update_local'),
                                   'hx-trigger': 'change',
                                   'hx-target': '#div_local',
                                   'hx-swap': 'outerHTML'}),
    )

    delivery_location = forms.ModelChoiceField(
        label="Local de Entrega/Obra",
        queryset=Empreendimento.objects.all().order_by('name'),
        widget=forms.Select(attrs={'class': 'form-control',
                                   'hx-get': reverse_lazy('compras:oc_update_cc'),
                                   'hx-trigger': 'change',
                                   'hx-target': '#div_cc',
                                   'hx-swap': 'outerHTML'}),
    )

This is my views:


def oc_update_local(request):
    company = request.GET.get('purchased_by')
    empresa = OurCompany.objects.get(pk=company)
    if empresa.definecat == 1:
        if empresa.name[:5] == "Cabiu":
            company = OurCompany.objects.get(name='Cabiunas Inc')
            empreendimentos = Empreendimento.objects.filter(
                company=company).order_by('name')
        elif empresa.name[:5] == "Coque":
            company = OurCompany.objects.get(
                name='Coqueiral Agropecuaria Matriz')
            empreendimentos = Empreendimento.objects.filter(
                company=company).order_by('name')
    else:
        empreendimentos = Empreendimento.objects.filter(
            company=company).order_by('name')
    return render(request, "compras/partials/oc_update_local.html", {"empreendimentos": empreendimentos})


def oc_update_cc(request):
    local = request.GET.get('delivery_location')
    ccs = CentroCusto.objects.filter(imovel=local).order_by('name')
    return render(request, "compras/partials/oc_update_cc.html", {"ccs": ccs})

And this is my html template:

<div class="form-row">
            <div class="form-group col-3">
                {{ form.purchased_by | as_crispy_field }}
            </div>
            <div class="form-group col-4" id="div_local">
                {{ form.delivery_location | as_crispy_field }}
            </div>
            <div class="form-group col-4" id="div_cc">
                {{ form.cc |as_crispy_field }}
            </div>
        </div>

And i have a partial for each update, but the second never triggers.

Thanks for the help

only one htmx request on browser happening

The issue you're encountering likely stems from the fact that the second <select> element (delivery_location) is not properly triggering the update of the third <select> element (cc). This could be happening because the hx-get for the third select is set to trigger on the second select (delivery_location), but there's no mechanism in place to pass the updated value from the second select to the third one.

Solution:

  1. Pass the delivery_location value to the oc_update_cc view: For HTMX to properly trigger the update of the third <select>, you need to ensure that the value from the second <select> is sent to the server when it triggers the request for the third <select>. This requires you to dynamically include the value of delivery_location in the HTMX request.
  2. Add an hx-get for the third select: You will need to dynamically update the third <select> based on the value of the second.

Here's a possible solution:

<div class="form-row">
    <div class="form-group col-3">
        {{ form.purchased_by | as_crispy_field }}
    </div>
    <div class="form-group col-4" id="div_local">
        {{ form.delivery_location | as_crispy_field }}
    </div>
    <div class="form-group col-4" id="div_cc">
        {{ form.cc |as_crispy_field }}
    </div>
</div>

Now, modify the delivery_location field to trigger the HTMX request for the third field:

delivery_location = forms.ModelChoiceField(
    label="Local de Entrega/Obra",
    queryset=Empreendimento.objects.all().order_by('name'),
    widget=forms.Select(attrs={
        'class': 'form-control',
        'hx-get': reverse_lazy('compras:oc_update_cc'),
        'hx-trigger': 'change',
        'hx-target': '#div_cc',
        'hx-swap': 'outerHTML',
        'hx-vals': '{ "delivery_location": this.value }',  # Dynamically send value of selected option
    }),
)

On views.py

def oc_update_cc(request):
    local = request.GET.get('delivery_location')  # This should now contain the value of the selected 'delivery_location'
    ccs = CentroCusto.objects.filter(imovel=local).order_by('name')
    return render(request, "compras/partials/oc_update_cc.html", {"ccs": ccs})

This approach should ensure that selecting an option in the second <select> triggers an HTMX request to update the third <select>, and the request will correctly include the selected value of the second field. Thank you so much! Wishing you a wonderful rest of the day! 😊

Back to Top