skip to Main Content

I have created a multiple select dropdown list which is opened when you click on a div. Then when you click inside the dropdown list it needs to be open to be able to select more than one thing. Then when you click outside of the dropdown it should close.

I got this code which works as expected, given the logs:

$(document).mouseup(function(e){
    if(!e.target.parentNode.id.includes('multipleSelectDropdown')){
        $('*[id*=multipleSelectDropdown]').css('display', 'none');
    console.log("Outside!");
    }
  else{
    console.log("Inside!");
  }
});

function clickedMultiSelectDropdown(optionsWrapperInput){
    var optionsWrapper = document.getElementById(optionsWrapperInput);
    if(optionsWrapper.style.display == 'none'){
        optionsWrapper.style.display = 'block';
    }
    else{
        optionsWrapper.style.display = 'none';
    }
}
.multiple-select-wrapper{
  width: 1000px;
  height: 1000px;
}
.multiple-select{
  cursor: pointer;
}
.multiple-select-options-wrapper {
  box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
}
.own-input-field{
    border: 1px solid rgb(180 180 180);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
  <div class="multiple-select-wrapper">
    <div class="multiple-select">

      <div class="own-input-field" tabindex="0" onclick="clickedMultiSelectDropdown('multipleSelectDropdownSize')">Size...</div>

      <div id="multipleSelectDropdownSize" class="multiple-select-options-wrapper" style="display: none;">
        <div class="multiple-select-options-item">1</div>
        <div class="multiple-select-options-item">2</div>
      </div>

    </div>
  </div>
</body>

If I click on the "Size…" element the box with options opens. When when I click on the box it logs "inside" and it stays open. When I click below or outside of all elements it says "outside" and the box closes.

Problem

For some reason though, when I click on the "Size…" div again when the box is open it again logs "outside" as expected, BUT the box doesn’t close. Why? This drives me mad…

3

Answers


  1. Chosen as BEST ANSWER

    I got some inspiration from both @KooiInc and @Pointy who nearly solved my issue. For my case below code did what I want. It will open the options when you click "Size...", keep the options open when you click them, and close them if you click anywhere else:

    document.addEventListener('mouseup', handleSearchClick);
    
    function handleSearchClick(evt){
    
        if(evt.target.classList.contains('own-input-field')){
            var optionsWrapper = evt.target.nextElementSibling;
            if(optionsWrapper.style.display == 'none'){
                optionsWrapper.style.display = 'block';
            }
            else{
                optionsWrapper.style.display = 'none';
            }
        }
        else if(!evt.target.classList.contains('multiple-select-options-item')){
            document.querySelectorAll('.multiple-select-options-wrapper').forEach((dropdownItem) => {
                dropdownItem.style.display = 'none';
            });
        }
    }
    .multiple-select-wrapper{
      width: 1000px;
      height: 1000px;
    }
    .multiple-select{
      cursor: pointer;
    }
    .multiple-select-options-wrapper {
      box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    }
    .own-input-field{
        border: 1px solid rgb(180 180 180);
    }
    <body>
      <div class="multiple-select-wrapper">
        <div class="multiple-select">
    
          <div class="own-input-field" tabindex="0">Size...</div>
    
          <div id="multipleSelectDropdownSize" class="multiple-select-options-wrapper" style="display: none;">
            <div class="multiple-select-options-item">1</div>
            <div class="multiple-select-options-item">2</div>
          </div>
    
        </div>
      </div>
    </body>

    Thank you both, couldn't have solved it without you!


  2. Your code is confusing. The use of 2 handlers creates a race condition, where mouseup wins (as @Pointy noted).

    Here is a plain js solution using event delegation, handling only click events and using classList.toggle to handle the showing/hiding of the values.

    It’s up to you to convert that to jquery (if deemed necessary).

    document.addEventListener(`click`, handle);
    
    function handle(evt) {
      if (!evt.target.closest(`#multipleSelectDropdownSize`)) {
        return document.querySelector(`#multipleSelectDropdownSize`)
          .classList.toggle(`visible`);
      }
      if (evt.target.classList
        .contains(`multiple-select-options-item`)) {
        return evt.target.classList.toggle(`selected`);
      }
    }
    .multiple-select-wrapper {
      width: 100px;
      height: 100px;
    }
    
    .multiple-select {
      cursor: pointer;
    }
    
    .multiple-select-options-wrapper {
      display: block;
    }
    
    #multipleSelectDropdownSize {
      display: none;
    }
    
    .visible {
      display: block !important;
    }
    
    .selected {
      background-color: blue;
      color: white;
    }
    
    .multiple-select-options-wrapper {
      box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    }
    
    .own-input-field {
      border: 1px solid rgb(180 180 180);
    }
    <div class="multiple-select-wrapper">
      <div class="multiple-select">
    
        <div class="own-input-field" tabindex="0">Size...</div>
    
        <div id="multipleSelectDropdownSize" class="multiple-select-options-wrapper">
          <div class="multiple-select-options-item">1</div>
          <div class="multiple-select-options-item">2</div>
        </div>
    
      </div>
    </div>
    Login or Signup to reply.
  3. Your "mouseup" handler fires for each element in the ancestry chain for the target element. When it bubbles to a point in the DOM where the parent id does not have the content you’re matching, it will hide the element.

    After that event has been dealt with, the browser fires the "click" event, and your handler for the select element will see that the select dropdown is hidden, and so it will open it back up.

    Here’s what I would do:

    $(document).on("click", ".own-input-field", function(e) {
     e.stopImmediatePropagation();
     $(this).closest(".multiple-select").find(".multiple-select-options-wrapper").show();
    });
    
    $(document).on("click", function(e) {
      e.stopImmediatePropagation();
      if ($(e.target).is(".own-input-field"))
        return;
      $(".multiple-select-options-wrapper").hide();
    });
    .multiple-select-wrapper{
      height: 100px;
    }
    .multiple-select{
      cursor: pointer;
    }
    .multiple-select-options-wrapper {
      box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    }
    .own-input-field{
        border: 1px solid rgb(180 180 180);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <body>
      <div class="multiple-select-wrapper">
        <div class="multiple-select">
    
          <div class="own-input-field" tabindex="0">Size...</div>
          
          <div class="multiple-select-options-wrapper" style="display: none">
            <div class="multiple-select-options-item">1</div>
            <div class="multiple-select-options-item">2</div>
          </div>
    
        </div>
      </div>
      
      This is other content.
    </body>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search