HTML form enable one list of options or another

Posted on

Problem

I’m trying to display a form where a user can select a specific item from a list or a specific category of items from another list. I want them to select one or the other, not both.

I followed this question which solves how to handle this in the backend.

I still need to figure out how to properly show this in the view.
I have the following sample which does what I would like to achieve, but I’m wondering if this is the way to go:

$('.formGroup input:checkbox').on('click', function() {
  var id = $(this).prop('id');
  var groups = $(this).parents('.formGroup').siblings('.formGroup');
  var thisGroup = $(this).parents('.formGroup');

  $('select', thisGroup).prop('disabled', false);

  $.each(groups, function(index, item) {
    var checkbox = $('input:checkbox', item);
    var select = $('select', item);

    checkbox.prop('checked', false);
    select.val(-1).prop('disabled', true);
  })
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="formGroup">
  <label>
    <input type="checkbox" value="" id="Option1">Select an Item</label>
  <select disabled="disabled">
    <option value=""></option>
    <option value="1">Item 1</option>
    <option value="2">Item 2</option>
    <option value="3">Item 3</option>
  </select>
</div>
<div class="formGroup">
  <label>
    <input type="checkbox" value="" id="Option2">Or select a Category</label>
  <select disabled="disabled">
    <option value=""></option>
    <option value="1">Category 1</option>
    <option value="2">Category 2</option>
    <option value="3">Category 3</option>
  </select>
</div>

Solution

Possible problem of the current solution

If you check one of the checkboxes, it gets activated and the select-element becomes enabled. If you click the same checkbox again, you only uncheck it, but the select-element stays enabled. I’d say there are two possibilities here:

  • disable the select-element as well
  • don’t let the user uncheck the input-element

In the following examples I went with the first option.
As requested in the comments, I’ve updated the review to work for the second option.

Reduce the number of DOM queries and cache selectors

You didn’t say how many of those groups are present or how often a user is going to make this decision. But you do a lot of the same DOM queries in your event handler over and over again.

At first let’s store the “group-selector” in a string, to make it re-usebale. Then select all groups:

const selector = '[data-form-group]';
const groups = $(selector);

You can stick to classes if you like. I tend to use data-*-attributes to couple JavaScript.


As we also often need the input– and the select-element in each group, let’s store them as well:

groups.each(function() {
    const group = $(this);
    group.data('checkbox', group.find('input'));
    group.data('select', group.find('select'));
});

Now we can access the form elements anytime, without re-querying the DOM.

The actual event handler

Attach the event handler to each input-element, the checkboxes radio-buttons. Then test, whether the current group is “enabled”, i.e. the input-element is checked:

If it is checked already

  • do nothing and simply return

If it is not checked

  • enable the select-element
  • run through all other groups and disable them

The final code could look like this:

const selector = '[data-form-group]';
const groups = $(selector);

groups.each(function() {
  const group = $(this);
  group.data('toggle', group.find('input'));
  group.data('options', group.find('select'));

  group.data('toggle').on('change', function() {
    const selectedGroup = $(this).closest(selector);

    if (!selectedGroup.data('toggle').is(':checked')) {
      return;
    }

    selectedGroup.data('options').prop('disabled', false);

    groups.each(function() {
      const current = $(this);

      if (selectedGroup[0] === current[0]) {
        return;
      }

      current.data('toggle').prop('checked', false);
      current.data('options').prop('disabled', true);
    });
  });
});

Try it yourself

Leave a Reply

Your email address will not be published. Required fields are marked *