2

This implementation is using Django 4.0 and Bootstrap5 with CrispyForms.

Objective: The user selecting a value in one field determines whether another field is shown or hidden. By default, the conditional field has a value of "No". The impacted field will be shown when the user changes the conditional field to the value of "Yes". Specifically, if the user selects "Yes" for the field Recurring event the field Recurrence pattern will be shown.

Please note that the implementation of Class Based Views in the template is working great. Here's a screenshot of the form (with the conditional field requirement not working): Working form screenshot

Existing code (relevant snippets only)

Here's what I have in models.py:

YES_NO_CHOICES = [
    ('No', 'No'),
    ('Yes', 'Yes'),
]
RECURRENCE_PATTERN_CHOICES = [
    ('---', '---'),
    ('Daily', 'Daily'),
    ('Weekly', 'Weekly'),
    ('Monthly', 'Monthly'),
    ('Yearly', 'Yearly'),
]


class Event(models.Model):
    event_name = models.CharField(
        max_length=70,
        help_text='''Enter a name for the event. This is a required field and is limited to 70 characters.'''
    )
    recurring_event = models.CharField(
        max_length=5,
        choices=YES_NO_CHOICES,
        default='No',
        help_text='''Is this a one off event or will it recur? Selecting Yes will open up additional fields.'''

    )
    recurrence_pattern = models.CharField(
        max_length=10,
        choices=RECURRENCE_PATTERN_CHOICES,
        default='---',
        help_text='''Select the recurrence pattern for this event.'''
    )

Here is what I have in forms.py:

class EventStaffSummaryUpdateView(UpdateView):
    """Event Staff Update view - allows staff to change event details"""
    model = Event
    template_name = 'events/event_staff_summary_form.html'
    fields = [
            'event_name',
            'recurring_event',
            'recurrence_pattern',
    ]
    context_object_name = 'event'

In the event_staff_summary.html template (using inheritance) I have:

   <div class="content-section">
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <div id="event_name">
                    {{ form.event_name|as_crispy_field }}
                </div>
                <div id="recurring_event">
                    {{ form.recurring_event|as_crispy_field }}
                </div>
                <div id="recurrence_pattern">
                    {{ form.recurrence_pattern|as_crispy_field }}
                </div>
            </fieldset>
            <div class="form-group pt-4 pb-2">
                {% if page_type == 'Update' %}
                    <button class="btn btn-BlueGray" type="submit">Update Event</button>
                {% else %}
                    <button class="btn btn-BlueGray" type="submit">Create Event</button>
                {% endif %}
            </div>
        </form>
    </div>

In the base.html template I am using the Google JQuery link (found on my journey as a simple way of implementing JQuery):

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

As you can see with the screenshot, the form itself is displaying perfectly. So models, form and even the html is working to this point. The update class based view is working with the DB. All that remains is to show or hide Recurrence pattern based on the value in the field Recurrence event. Which brings me to...

What have I tried so far?

Of the 10+ JS snippets I've come across and tried, here is the leading candidate that seems to be closest. I really want this to work as it makes sense to me.

    <script>
        $("#recurring_event").change(function() {
            if ($(this).val() === "Yes") {
                $('#recurrence_pattern').show();
            } else {
                $('#recurrence_pattern').hide();
            }
         });
    </script>

Request

Has anyone got suggestions on how I can get this working? I've got requirements for a number of conditionally displayed fields. I'd prefer to not work from checkboxes as typically this client prefers to explicitly have the user click Yes or No as this is clearer to them (they feel there is no chance of ambiguity with a closed question and a yes/no choice).

This requirement of conditional fields in forms is implemented in many instances, so I know I'm not seeking the impossible. I am hoping that there's a simple refinement (or clean up) of the javascript snippet I've posted. I also welcome other JS suggested snippets too.

Thanks in advance for your help.

ANSWER (Feb 27) Following the issuance of a bounty @Swati came through with a solution posted in a fiddle here: https://jsfiddle.net/L8ke03hc/ As soon as they post the answer I'll award the Bounty. I'd like to thank Tony for coming really close and getting me on the right track. The final piece of the puzzle was the .trigger event to call the change function.

    <script>
        $(document).ready(function() {
          $("#id_recurring_event").change(function() {
            if ($(this).val() === "No") {
              $('#div_id_recurrence_pattern').hide();
            } else {
              $('#div_id_recurrence_pattern').show();
            }
          });
          $("#id_recurring_event").trigger("change")
        })
    </script>

Thanks to all that came through on this one. This was a profound learning experience for me. I really need to spend some time learning JS. That said, I've got the solution. May anyone trying to build conditional logic in Django/CrispyForms benefit from this. I am so grateful for the Open Source community! <3

11
  • 1
    Observation: The change event is for <select> but your selector appears to be a <div>. Do you actually have the correct $(this).val()? i.e. is it ever === "Yes". Without context I can't tell what that is. Commented Feb 14, 2022 at 20:24
  • In models.py the YES_NO_CHOICES constant variable has "Yes" and "No". (this).val() === "Yes" should be correct. I did double/triple check that, but I appreciate the observation. As for <div> verses <select> this may be my lack of JS experience. I had read through research that the id was key. Assigning that to a div tag should allow it to work. AND my lack of JS chops may mean I'm not doing this right. Commented Feb 14, 2022 at 20:27
  • 1
    Unless you have other JS that binds <select> to <div>, that event will not fire on a div. More on that: developer.mozilla.org/en-US/docs/Web/API/HTMLElement/…. Commented Feb 14, 2022 at 20:44
  • 1
    What does {{ form.recurring_event|as_crispy_field }} render? I would inspect DOM and look for the actual form. From there it should be easy to see where <select> is and use JS selectors to select it. Then update that jQuery snippet. Are you able to post that source code? Happy to put it together Commented Feb 14, 2022 at 21:09
  • 1
    Check this and try again :) Commented Feb 27, 2022 at 5:58

2 Answers 2

2

Update library to <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Wrap function in a DOM ready event.

Update selector to a <select> (from div). Do this by inspecting DOM.

End result:

(function($){
    $(document).ready(function(){
        $("#id_recurring_event").change(function() {
            if ($(this).val() === "Yes") {
                $('#id_recurrence_pattern').show();
            } else {
                $('#id_recurrence_pattern').hide();
            }
        });
    })
})(jQuery);

Sign up to request clarification or add additional context in comments.

4 Comments

It turns out that I'm missing one element - the JS to cover on page load. As it stands, this works if I change the field. What's missing is the element that ensures it works on every page load. Currently it works only when I change the field.
Unless I'm misunderstanding what you're saying, this should work on every page load. Assuming that script is on every page.
I have been caught up on other things. However, I am going to rebuild the form, get it working properly and then inject the JS to test. I will follow up and let you know. Your confidence in this is inspiring. Thanks for your efforts. Much appreciated, and a reflection of what a great community can be <3
I've returned to this. I have built a new create form, and while the conditional field works after refreshing it does not work on page load. I shall continue to test.
1
+50

You can use trigger() method to achieve this . So, whenever your page gets load called this to execute the change event which is attached on select-box .

Working code :

$(document).ready(function() {
  $("#id_recurring_event").change(function() {
    if ($(this).val() === "No") {
      $('#recurrence_pattern').hide();
    } else {
      $('#recurrence_pattern').show();
    }
  });
  $("#id_recurring_event").trigger("change")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<div class="content-section">
  <form method="POST">
    <fieldset class="form-group">
      <div id="event_name">
        ABC ..
      </div>
      <div id="recurring_event">
        <select id="id_recurring_event">
          <option value="Yes">Yes</option>
          <option value="No" selected="true">No</option>
        </select>
      </div>
      <div id="recurrence_pattern">
        somethings ..................
      </div>
    </fieldset>
  </form>
</div>

1 Comment

Thanks very much again. The addition of $("#id_recurring_event").trigger("change") really was the final missing element. Great work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.