javascripthtmljquerycssmulti-select

Jquery multi select dropdown with checkbox


I'm trying to achieve jquery multi select dropdown with checkboxes with customized apply and cancel button inside dropdown. When I select Select All, dropdown is closing unexpectedly, even I tried to use stopPropagation but still it is closing the dropdown.

Any help would be highly appreciated

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>MultiSelect with Fixed Select All</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

  <!-- MultiSelect CSS & JS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.css">
  <script src="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.min.js"></script>

</head>
<body>

<h2>Select Options</h2>
<select id="my-select" multiple>
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
  <option value="date">Date</option>
</select>
</body>
</html>

    
    $(document).ready(function () {
  $('#my-select').multiselect({
    placeholder: 'Select fruits',
    onControlOpen: function () {
      const $optionsContainer = $('.ms-options');

      // Add Select All checkbox once
      if ($('.select-all-container').length === 0) {
        const $selectAllContainer = $(`
          <div class="select-all-container">
            <label><input type="checkbox" id="select-all-checkbox"> Select All</label>
          </div>
        `);
        $optionsContainer.prepend($selectAllContainer);

        // Real fix: Stop mousedown before plugin closes the dropdown
        $(document).on('mousedown', function (e) {
          if ($(e.target).closest('.select-all-container').length) {
            e.stopPropagation();
          }
        });

        $('#select-all-checkbox').on('change', function () {
          const isChecked = $(this).is(':checked');
          $('#my-select option').prop('selected', isChecked);
          $('#my-select').multiselect('reload');
        });
      }

      // Add Apply/Cancel buttons once
      if ($('.custom-button-wrapper').length === 0) {
        const $wrapper = $('<div class="custom-button-wrapper"></div>');

        const $apply = $('<button class="custom-button">Apply</button>').on('click', function () {
          const selected = $('#my-select').val();
          alert('Selected: ' + (selected ? selected.join(', ') : 'None'));
        });

        const $cancel = $('<button class="custom-button cancel">Cancel</button>').on('click', function () {
          $('#my-select').val([]).multiselect('reload');
          $('.ms-parent').find('.ms-drop').hide();
        });

        $wrapper.append($apply).append($cancel);
        $optionsContainer.append($wrapper);
      }
    }
  });
});
.custom-button {
      display: inline-block;
      margin: 10px 5px 5px;
      padding: 5px 10px;
      background-color: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    .custom-button.cancel {
      background-color: #dc3545;
    }
    .custom-button-wrapper {
      text-align: center;
      padding-bottom: 10px;
    }
    .select-all-container {
      padding: 5px 10px;
      border-bottom: 1px solid #ccc;
      background: #f9f9f9;
      user-select: none;
    }
    
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>MultiSelect with Fixed Select All</title>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

  <!-- MultiSelect CSS & JS -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.css">
  <script src="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.min.js"></script>

</head>
<body>

<h2>Select Options</h2>
<select id="my-select" multiple>
  <option value="apple">Apple</option>
  <option value="banana">Banana</option>
  <option value="cherry">Cherry</option>
  <option value="date">Date</option>
</select>
</body>
</html>


Solution

  • We can enable selectAll property in the multiselect options.

    $(document).ready(function () {
      $('#my-select').multiselect({
      selectAll: true,
      ...
    

    Then use CSS to not destroy (display: none) but just hide (visibility:none) and make it look hidden using (position: absolute; left:-9999px) using the below CSS.

    a.ms-selectall.global {
      visibility: hidden;
      position: absolute;
      left: -9999px;
    }
    

    Finally on button click, we find this select all element and click it.

        $('#select-all-checkbox').on('change', function(e) {
          e.preventDefault();
          const isChecked = $(this).is(':checked');
          // $('#my-select option').prop('selected', isChecked);
          $('#select-all-checkbox').parents('.select-all-container').siblings('.ms-selectall.global').click();
          $('#select-all-checkbox').prop('checked', checkAllSelected(element));
        });
    

    When the options are changed, we need to manage the state of the select all checkbox, for this we use the event onOptionClick.

    onOptionClick: function(element) {
      $('#select-all-checkbox').prop('checked', checkAllSelected(element));
    },
    

    function checkAllSelected(selectElement) {
      var selectedOptions = $(selectElement).find('option:selected');
      var allOptions = $(selectElement).find('option');
      return selectedOptions.length === allOptions.length;
    }
    
    $(document).ready(function() {
      $('#my-select').multiselect({
        selectAll: true,
        placeholder: 'Select fruits',
        onOptionClick: function(element) {
          $('#select-all-checkbox').prop('checked', checkAllSelected(element));
        },
        onControlOpen: function(element) {
          const $optionsContainer = $('.ms-options');
    
          // Add Select All checkbox once
          if ($('.select-all-container').length === 0) {
            const $selectAllContainer = $(`
              <div class="select-all-container">
                <label><input type="checkbox" id="select-all-checkbox"> Select All</label>
              </div>
            `);
            $optionsContainer.prepend($selectAllContainer);
    
            // Real fix: Stop mousedown before plugin closes the dropdown
            $(document).on('mousedown', function(e) {
              if ($(e.target).closest('.select-all-container').length) {
                e.stopPropagation();
              }
            });
    
            $('#select-all-checkbox').on('change', function(e) {
              e.preventDefault();
              const isChecked = $(this).is(':checked');
              // $('#my-select option').prop('selected', isChecked);
              $('#select-all-checkbox').parents('.select-all-container').siblings('.ms-selectall.global').click();
              $('#select-all-checkbox').prop('checked', checkAllSelected(element));
            });
          }
    
          // Add Apply/Cancel buttons once
          if ($('.custom-button-wrapper').length === 0) {
            const $wrapper = $('<div class="custom-button-wrapper"></div>');
    
            const $apply = $('<button class="custom-button">Apply</button>').on('click', function() {
              const selected = $('#my-select').val();
              $('#my-select').next('.ms-options-wrap').removeClass('ms-active');
              alert('Selected: ' + (selected ? selected.join(', ') : 'None'));
            });
    
            const $cancel = $('<button class="custom-button cancel">Cancel</button>').on('click', function() {
              $('#my-select').val([]).multiselect('reload');
              $('.ms-parent').find('.ms-drop').hide();
            });
    
            $wrapper.append($apply).append($cancel);
            $optionsContainer.append($wrapper);
          }
        }
      });
    });
    .custom-button {
      display: inline-block;
      margin: 10px 5px 5px;
      padding: 5px 10px;
      background-color: #007bff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    
    .custom-button.cancel {
      background-color: #dc3545;
    }
    
    .custom-button-wrapper {
      text-align: center;
      padding-bottom: 10px;
    }
    
    .select-all-container {
      padding: 5px 10px;
      border-bottom: 1px solid #ccc;
      background: #f9f9f9;
      user-select: none;
    }
    
    a.ms-selectall.global {
      visibility: hidden;
      position: absolute;
      left: -9999px;
    }
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>MultiSelect with Fixed Select All</title>
      <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    
      <!-- MultiSelect CSS & JS -->
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.css">
      <script src="https://cdn.jsdelivr.net/gh/nobleclem/jQuery-MultiSelect/jquery.multiselect.min.js"></script>
    
    </head>
    
    <body>
    
      <h2>Select Options</h2>
      <select id="my-select" multiple>
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
        <option value="cherry">Cherry</option>
        <option value="date">Date</option>
      </select>
    </body>
    
    </html>