I am building a django wizard form with multiple form, however in one of the forms i have a field of small list of sectors, and when the user select a sector i trigger a function that fetches the sub-sectors of that particular sector. the problem is when i tested the form in a separated html template it works fine, but when i use it in my wizard form it does not update the ui even though in the console i can see that the request was successful.
#urls.py
from django.urls import path # type: ignore
from django.utils.translation import gettext_lazy as _ # type: ignore
from core import views
app_name = 'core'
urlpatterns = [
path('', views.OnboardingSessionWizardView.as_view(views.FORMS), name='start'),
path('sub-sectors/', views.get_subsectors, name='get-sub-sectors'),
path('get-started/', views.OnboardingSessionWizardView.as_view(views.FORMS), name='get-started'),
]
here is my view.py:
from core.forms import *
from formtools.wizard.views import SessionWizardView # type: ignore
from django.http import HttpResponse, JsonResponse, HttpRequest # type: ignore
from django.utils.translation import gettext_lazy as _ # type: ignore
from django.shortcuts import render,get_object_or_404 # type: ignore
from django.core.serializers import serialize # type: ignore
from core.models import *
from core.forms import *
# Create your views here.
FORMS = [("contact", EntryInformationForm),
("information", PersonalInformationForm),
("business", BusinessActivityForm),
("address", BusinessAddressForm),
]
TEMPLATES = {
"contact": "forms/core/_entry_information.html",
"information": "forms/core/_personal_information.html",
"business": "forms/core/_business_activity.html",
"address": "forms/core/_address.html"
}
def get_subsectors(request):
subsectors = []
sector_id = request.GET.get('sector')
try:
sector = get_object_or_404(Sector, name = sector_id)
subsectors = sector.subsectors.all()
except:
subsectors = []
subsectors_data = serialize('json', subsectors)
return render(request, 'partials/subsector_options.html', {'subsectors': subsectors})
class OnboardingSessionWizardView(SessionWizardView):
# form_list = [
# (_('CONTACT'),UserEntryInformationForm),
# (_('INFORMATIONS PERSONNELLES'),UserPersonalInformationForm),
# (_('VOTRE ACTIVITÉ '),UserBusinessActivityInformationForm), # Business Information
# ]
# template_name = 'onboarding.html'
form_list = FORMS
def get_template_names(self):
print(f"Current step: {self.steps.current}")
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
return HttpResponse('Onboarding process done')
def get_context_data(self, form, **kwargs):
context = super().get_context_data(form=form, **kwargs)
context['countries'] = Country.objects.all()
return context
and this is my business activity template where i use that form:
{% extends "_base.html" %}
{% load i18n static %}
{% load widget_tweaks %}
{% block inner %}
<div class="container mx-auto px-4 py-8">
<ol class="flex items-center justify-between gap-2 text-xs font-medium text-gray-500 sm:gap-4 w-full mb-4 sm:mb-5">
{% for step in wizard.steps.all %}
{% if forloop.counter0 > wizard.steps.index %}
<li class="flex items-center justify-end gap-2">
<span class="size-6 rounded bg-gray-50 text-center text-[10px]/6 font-bold text-gray-600">
{{ forloop.counter }}
</span>
<span> </span>
</li>
{% elif forloop.counter0 < wizard.steps.index %}
<li class="flex">
<span class="rounded bg-green-200 p-1.5 text-green-600">
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
</span>
</li>
{% else %}
<li class="flex items-center justify-center flex-grow gap-2 text-blue-600">
<span class="size-6 rounded bg-blue-50 text-center text-[10px]/6 font-bold">{{ forloop.counter }}</span>
<span>{{ step }}</span>
</li>
{% endif %}
{% endfor %}
</ol>
<form action="" class="space-y-4" method="POST">
{% csrf_token %}
{{ wizard.management_form }}
<!-- FORM FIELDS -->
<!-- Sector Field -->
<div>
<div class="relative mt-1.5">
<label for="{{ wizard.form.sector.name }}"> Domain d'activité </label>
<input
type="text"
name="{{ wizard.form.sector.html_name }}"
id="{{ wizard.form.sector.id_for_label }}"
placeholder="{{ wizard.form.sector.field.widget.attrs.placeholder }}"
list="sectorsList"
class="w-full rounded-lg border-gray-300 pe-10 text-gray-700 sm:text-sm [&::-webkit-calendar-picker-indicator]:opacity-0"
required
autocomplete="on"
hx-get="{% url 'core:get-sub-sectors' %}"
hx-trigger="change"
hx-vals="value"
hx-target="#sub-sectors-list"
hx-swap="innerHTML"
/>
<datalist id="sectorsList">
{% for value, label in wizard.form.sector.field.choices %}
<option value="{{ label }}" data-id="sector_{{value }}"> {{ label }} </option>
{% endfor %}
</datalist>
</div>
</div>
<!-- Sub Sector Field -->
<div id="sub-sectors-list">
{% include "partials/subsector_options.html" %}
</div>
<!-- REST of the form ...... -->
</form>
</div>
{% endblock %}
This my sub-sectors partial html template:
{% if subsectors %}
<div class="relative mt-1.5">
<label for="subsectors">Secteur d'activité</label>
<input
type="text"
name="subsectors"
placeholder="Secteur d'activité"
list="subsectors-list"
class="w-full rounded-lg border-gray-300 pe-10 text-gray-700 sm:text-sm [&::-webkit-calendar-picker-indicator]:opacity-0"
autocomplete="off"
value="{{subsectors.first}}"
/>
<datalist id="subsectors-list">
{% for subsector in subsectors %}
<option value="{{ subsector.name }}" data-id="{{ subsector.id }}">{{ subsector.name }}</option>
{% endfor %}
</datalist>
</div>
{% endif %}
and finally, here is my forms.py:
class BusinessActivityForm(forms.ModelForm):
activity_type = forms.ChoiceField(
widget=forms.RadioSelect(),
choices=BusinessActivity.BUSINESS_CHOICES,
label=_("Avez-vous déjà exercé une activité non-salariée ?"),
initial=BusinessActivity.BUSINESS_CHOICES[0][0]
)
class Meta:
model = BusinessActivity
fields = ['sector','when_to_start','commercial_name','activity_type']
widgets = {
'sector': forms.Select(attrs={
'placeholder': _("Domaine d'activité "),
'label': _("Domaine d'activité "),
}
),
'when_to_start': forms.DateInput(attrs={'placeholder': _('DD-MM-YYYY'), 'type': 'date'}),
'commercial_name': forms.TextInput(attrs={'placeholder': _('Nom comercial (optionnel)')}),
}
I tried everything but i can’t get it to work. is there a better approach since the list of sub-categries is quite large and my main aim to do it this way is to give the user the ability to type and have legit autocomplete suggestions