1

I have a dropdown menu that allows multiple selections. Now I want to make it when one particular option has selected all others to be disabled and enabled for selection. If that one particular is de-selected all others should be enabled again.

This is my select dropdown:

<select class="input-fields selectpicker" id="select_heigh" name="search[]" multiple>
    <option value="all" selected>Search all</option>
    <option value="tag">Tags</option>
    <option value="username">Username</option>
    <option value="email">Email</option>
    <option value="full_name">Full Name</option>
</select>

And here is what I have tried for the js

$(document).ready(function() {
    $('.selectpicker').selectpicker();
    $('.selectpicker').on('change', function() {
        if ($('option[value="all"]', this).is(':selected') && $(this).val().length > 1) {
            $('option[value="all"]', this).prop('selected', false);
            $('.selectpicker').selectpicker('refresh');
        }

        var selected = $(this).val();
        if (selected.includes("tag")) {
            $('option[value!="tag"]', this).prop('disabled', true);
        } else {
            $('option[value!="tag"]', this).prop('disabled', false);
        }

        if (selected.length > 3) {
            $(this).selectpicker('setStyle', 'selected-count', 'btn-danger');
            $(this).selectpicker('setTitle', selected.length + ' select(s)');
        } else {
            $(this).selectpicker('setStyle', 'selected-count', 'btn-default');
            $(this).selectpicker('setTitle', 'Select');
        }
    });
});

I want when "Tag" is selected the other options to be disabled. When "Tag" is de-selected the others are enabled. When any other option is selected to no effect on others.

Also, the counting of selected choices doesn't work as expected. It should start showing Selected(3), Selected(4) ... after the third selection. Currently, it shows all of them not count of them.

I'm not that familiar with JS and not sure if I'm on the right path here

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Jake
  • 59
  • 6
  • Check [this](https://stackoverflow.com/questions/4271463/how-to-style-a-disabled-checkbox#:~:text=input%5Btype%3Dcheckbox%5D%5Bdisabled%5D%7B) out – Jovan Jovanovic Feb 07 '23 at 11:27
  • Thanks but I'm still unable to fix the issue. – Jake Feb 07 '23 at 11:33
  • I'm confused. If clicking on one option is meant to "disable" all the others doesn't that defeat the purpose of having the select as "multiple"? – Andy Feb 07 '23 at 11:36
  • I understand what you mean but there will have around 10 options and If this option is not clicked there is no problem to click on multiple options. I just show additional filters when it is only that option is clicked. – Jake Feb 07 '23 at 11:38
  • 1
    This seems a confusing UI, I'd personally suggest using a checkbox `` to offer the choice of the option that disables all others, and the ` – David Thomas Feb 07 '23 at 12:52

1 Answers1

1

What the OP wants to achieve is a rather unexpected behavior of a native form control.

And in case one changes the behavior it should be based on using what form elements or elements in particular do support natively like the disabled- and the dataset-property.

An implementation then could be as simple as querying the correct select element and subscribing an event listener to any click event which occurres on the very select element. The change event can not be used since any further changes are impossible once a single option is selected but all other option are disabled. An option element's dataset gets used as lookup in order to detect whether the very element already has been selected before the current click handling.

function handleOptionClickBehavior({ target }) {
  const optionNode = target.closest('option');

  const nodeValue = optionNode?.value;
  if (nodeValue === 'tag') {

    const optionNodeList = [...optionNode.parentNode.children]
      .filter(node => node !== optionNode);

    const { dataset } = optionNode;
    if (dataset.hasOwnProperty('selectedBefore')) {

      Reflect.deleteProperty(dataset, 'selectedBefore');
      optionNode.selected = false;

      optionNodeList
        .forEach(node => node.disabled = false);
    } else {
      dataset.selectedBefore = '';

      optionNodeList
        .forEach(node => node.disabled = true);
    }
  }
}

document
  .querySelector('.selectpicker')
  .addEventListener('click', handleOptionClickBehavior)
body { zoom: 1.2 }
<select class="input-fields selectpicker" id="select_heigh" name="search[]" size="5" multiple>
  <option value="all" selected>Search all</option>
  <option value="tag">Tags</option>
  <option value="username">Username</option>
  <option value="email">Email</option>
  <option value="full_name">Full Name</option>
</select>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • Thanks for the help. I still don't understand why this is bad UI. How should be done if not like this? – Jake Feb 07 '23 at 13:11
  • @Jake, because it seems to go against expectations of how the web works (at least, that's how I personally feel about it); it may be worth asking a question over on one of our sister sites, specifically: [ux.se]. – David Thomas Feb 07 '23 at 13:16
  • Thanks, I will ask there for any suggestions. – Jake Feb 07 '23 at 13:19
  • Because if a user choses something they expect to chose again if they pick the wrong choice. With an approach like this you are going against accessibility guidelines. – cloned Feb 07 '23 at 13:32