# Conditional display of specific parts of a form

**URL:** <https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442>\
**Category:** Forms & APIs\
**Created:** [October 10, 2023, 2:08pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442 "2023-10-10T14:08:33Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![JeremyG](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jeremyg/32/13496_2.png) [@JeremyG](https://forum.djangoproject.com/u/JeremyG)\
**Post date:** [October 10, 2023, 2:08pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/1 "2023-10-10T14:08:34Z")

</div>

I’m building a form with Django and trying to get the following behaviour:

Among 4 possible answers on question `genre`, if the user chooses the answer `AUTRE`, display question `genre_preciser` and make the answer mandatory. Otherwise, do not display `genre_preciser`.

I’d like to use something similar to htmx, as my proficiency in Javascript is close to 0.

I’ve been [asking the question](https://www.reddit.com/r/htmx/comments/1743i5j/how_to_dynamically_load_a_form_element_depending/) to the htmx community and understand that on htmx side, I would have to deal with `hx-get`. However I’m rather lost from here: what URL do I have to pass? The whole form is on a single page, I don’t have any separate URL.

How would you do? Is there an easier way to do this?

Thanks in advance!

`models.py`

```auto
class Questionnaire(models.Model):

    class Genre(models.TextChoices): 
        FEMININ = 'Féminin', _('Féminin')
        MASCULIN = 'Masculin', _('Masculin')
        AUTRE = 'Autre', _('Autre (préciser)')
    genre = models.CharField(
        choices=Genre.choices,
        null=True,
        blank=False
    )
    genre_preciser = models.TextField(
        null=True,
        blank=True
    )

```

`forms.py`

```auto
class QuestionnaireForm(forms.ModelForm):
  
  class Meta:
    model = Questionnaire
    fields = ['genre', 'genre_preciser']

```

`views.py`

```auto
class CreerSoumission(CreateView):
    model = Questionnaire
    form_class = QuestionnaireForm
    template_name = 'template.html'

```

`urls.py`

```auto
urlpatterns = [
    path('', views.CreerSoumission.as_view(), name='soumettre'),
]

```

`template.html`

```auto
  <form action="" method="post">
    {% csrf_token %}
    <table>
    {{ form.as_table }}
    </table>
    <input type="submit" value="Submit">
  </form>

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 10, 2023, 7:42pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/2 "2023-10-10T19:42:28Z")

</div>

Keep in mind that if you modify the form in the browser, you will also need to know to do this in the view when you’re binding the submitted data to the form.

Yes, you could do this using HTMX, but I think you’re going to find that it’s not going to save you a lot of effort without doing some refactoring of your code, form, and templates.

When we have a requirement like this, we still find it easier to use JavaScript. (If you really want to avoid writing JavaScript and would prefer using a more declarative method, check out [Alpine.js](https://alpinejs.dev/).)

What we do is create the form, with the additional field(s) in a div with a css class having a [`display:none`](https://developer.mozilla.org/en-US/docs/Web/CSS/display#box). You can then attach an event listener to `genre`, and on a `change` event check the value. If the value is now `AUTRE`, remove that class from the div.

Your form’s `clean` method will then need to check the `genre` field to determine whether the `genre_preciser` field has been filled out.

Otherwise, to do this appropriately with HTMX, you’re looking at creating a new view for HTMX to call, a new form for this new field, and a template to render that field. (And you still need to create the `clean` method on the form as well as figure out how you’re going to bind the data when it’s POSTed.)

(You could simplify this a _little_ by taking an approach similar to the JavaScript in that you define the form as having that field. Then, in processing the `GET` for the view, you remove that field from the form before rendering it. This handles the binding issue for the data as the field is always defined in the form, but that’s about all it does for you.)

There may be an easier way - but like I started out with, we’ve found it easiest in this situation just to use the JavaScript.

---

<div class="post-metadata">

**Author:** ![JeremyG](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jeremyg/32/13496_2.png) [@JeremyG](https://forum.djangoproject.com/u/JeremyG)\
**Post date:** [October 24, 2023, 1:54pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/3 "2023-10-24T13:54:11Z")

</div>

Thank you Ken for your answer. I went the jQuery route and it ended up working fine with a dropdown list of choices (one single choice possible). Here’s the script I wrote for reference (and for others!):

```auto
$(document).ready(function() {
  const genre = $("[name='qdem01_genre']");
  const genrePreciser = $("[name='qdem01rx_genre_precis']").closest(".questionWrapper");
  genrePreciser.addClass('hidden');
  genre.on('change', function() {
    if (this.value === "Autre") {
      genrePreciser.removeClass('hidden');
    } else {
      genrePreciser.addClass('hidden');
    }
  });
});

```

However, I’m running now into a similar issue, but with a different type of field, and this approach doesn’t seem to work here.

The field `qdem05_statut` has type `ModelMultipleChoiceField`. I want to display the following field, `qdem05b_statut_preciser`, only when the value `Autre : précisez` is selected as a choice. I’ve been trying to do it with jQuery but with no success so far.

Here is the data (including the script at the end):

`forms.py`

```auto
class AdherentForm(forms.ModelForm):
    qdem05_statut = forms.ModelMultipleChoiceField(
        queryset=Statut.objects.order_by('id'),
        widget=forms.CheckboxSelectMultiple,
        label=('Quel est votre statut actuel ? (Plusieurs réponses possibles) *')
        )

    class Meta:
        model = Adherent
        fields = ['qdem05_statut', 'qdem05b_statut_preciser']

    def __init__ (self, *args, **kwargs):
        kwargs.setdefault('label_suffix', '')
        super(AdherentForm, self). __init__ (*args, **kwargs)

```

`models.py`

```auto
class Statut(models.Model):
    name = models.CharField(
        max_length=100,
        unique=True,
        blank=False
    )

    def __str__ (self):
        return self.name

class Adherent(models.Model):

    qdem05a_statut = models.ManyToManyField(
        Statut, 
        verbose_name="Quel est votre statut actuel ? (Plusieurs réponses possibles) *",
        related_name='adherent_statut'
    )
    qdem05b_statut_preciser = models.TextField(
        _('Préciser :'),
        null=True,
        blank=True
    )

```

`template.html`

```auto
   <div name="statut" class="questionWrapper" id="statut">

      <p>{{ form.qdem05_statut.errors }}</p>
      <h5>{{ form.qdem05_statut.label_tag }}</h5>
      <p>{{ form.qdem05_statut }}</p>
    </div>

    <div name="statut_preciser" class="questionWrapper" id="statut_preciser">
      <p>{{ form.qdem05b_statut_preciser.errors }}</p>
      <p>{{ form.qdem05b_statut_preciser }}</p>
    </div>

```

`script.js`

```auto
$(document).ready(function() {
    function toggleStatutPreciser() {
        var selectedValues = $('input[name="qdem05_statut"]:checked').map(function() {
            return this.value;
        }).get();

        if (!selectedValues.includes("Autres : précisez")) {
            $('#statut_preciser').hide();
        } else {
            $('#statut_preciser').show();
        }
    }

    toggleStatutPreciser();

    $('input[name="qdem05_statut"]').on('change', toggleStatutPreciser);
});

```

Any suggestions would be very welcome. Thanks!

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 24, 2023, 2:50pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/4 "2023-10-24T14:50:13Z")

</div>

Depending upon a couple of different factors, such as the possibility of a custom widget being used, your css selector may not be correct.

In a simple test case that I just looked at, the selector ended up being:  
`$('select[name="q05"]>option:selected')...`

You’ll want to verify this in your own environment.

---

<div class="post-metadata">

**Author:** ![JeremyG](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jeremyg/32/13496_2.png) [@JeremyG](https://forum.djangoproject.com/u/JeremyG)\
**Post date:** [October 24, 2023, 8:17pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/5 "2023-10-24T20:17:01Z")

</div>

I tried this:

```auto
$(document).ready(function() {
    function toggleStatutPreciser() {
        var selectedValues = $('select[name="qdem05_statut"]>option:selected').map(function() {
            return this.value;
        }).get();

        if (!selectedValues.includes("Autres : précisez")) {
            $('#statut_preciser').hide();
        } else {
            $('#statut_preciser').show();
        }
    }

    toggleStatutPreciser();
    $('input[name="qdem05_statut"]').on('change', toggleStatutPreciser);
});

```

the element that has `statut_preciser` as id is hidden at load, but nothing happens when I select/check `Autres : précisez`…

(I should mention also that `qdem05_statut` has the id `statut`)

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 25, 2023, 12:29am UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/6 "2023-10-25T00:29:46Z")

</div>

> [@KenWhitesell](#):
>
> You’ll want to verify this in your own environment.

Without seeing the actual html that has been rendered and sent to the browser, there’s no way for us to know what you need to use here. There’s not going to be a generic answer that we can provide.

Also keep in mind that your selector for the event needs to match as well.

---

<div class="post-metadata">

**Author:** ![JeremyG](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/jeremyg/32/13496_2.png) [@JeremyG](https://forum.djangoproject.com/u/JeremyG)\
**Post date:** [October 25, 2023, 9:04am UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/7 "2023-10-25T09:04:41Z")

</div>

Right. Of course 🤦‍♂️ Thanks for taking the time to clearly state the obvious 🙂

Using firefox dev tools inspector, here’s what the targeted checkbox looks like:

```auto
<label for="id_qdem05_statut_18">
  <input type="checkbox" name="qdem05_statut" value="20" id="id_qdem05_statut_18">
   Autres : précisez
 </label>

```

So the id is `id_qdem05_statut_18`, which is new to me but makes sense.

I tried to modify the script as follows but it still doesn’t seem to work:

```auto
$(document).ready(function() {
    function toggleStatutPreciser() {
        var selectedValues = $('#id_qdem05_statut_18 option:selected').map(function() {
            return this.value;
        }).get();

        if (!selectedValues.includes("Autres : précisez")) {
            $('#statut_preciser').hide();
        } else {
            $('#statut_preciser').show();
        }
    }

    toggleStatutPreciser();
    $('#id_qdem05_statut_18').on('change', toggleStatutPreciser);
});

```

I tried another approach, with no success either yet:

```auto
$(document).ready(function() {
    function toggleStatutPreciser() {
// Here I alternatively asked for the value "Autres : précisez" or for 20
        var isChecked = $('#id_qdem05_statut_18 input[value="Autres : précisez"]').is(':checked');

        if (isChecked) {
            $('#statut_preciser').show();
        } else {
            $('#statut_preciser').hide();
        }
    }

    toggleStatutPreciser();
    $('#id_qdem05_statut_18 input').on('change', toggleStatutPreciser);
});

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [October 25, 2023, 12:30pm UTC](https://forum.djangoproject.com/t/conditional-display-of-specific-parts-of-a-form/24442/8 "2023-10-25T12:30:16Z")

</div>

So this is different than a regular multi-select list - you’re rendering each option as a checkbox which does change things.

You don’t need to “search” for the element, you can reference it directly to see whether or not it’s checked.

I’m not sure you can necessarily guarantee that the `id` is going to remain a constant - especially if other options are added to the set. I believe the selector you may want would be:  
`$('input[name="qdem05_statut"][value="20"]:checked')`  
You could then check the `length` attribute of that to see whether a value was returned.  
(I suggest you check this out in your browser’s console to make sure I’ve got the syntax right - I’m winging this right now.)
