#109 - Custom Multi Selects v0.1

Custom-styled multi selects with search, keyboard selection, and more.

View demo project
Voir la démo

<!-- 💙 MEMBERSCRIPT #109 v0.1 💙 - CUSTOM MULTI SELECT -->
<script>
  $(document).ready(function() {
    $('[ms-code-select-wrapper]').each(function() {
      const $wrapper = $(this);
      const isMulti = $wrapper.attr('ms-code-select-wrapper') === 'multi';
      const $input = $wrapper.find('[ms-code-select="input"]');
      const $list = $wrapper.find('[ms-code-select="list"]');
      const $selectedWrapper = $wrapper.find('[ms-code-select="selected-wrapper"]');
      const $emptyState = $wrapper.find('[ms-code-select="empty-state"]');
      const options = $input.attr('ms-code-select-options').split(',').map(opt => opt.trim());

      let selectedOptions = [];
      let highlightedIndex = -1;

      const $templateSelectedTag = $selectedWrapper.find('[ms-code-select="tag"]');
      const templateSelectedTagHTML = $templateSelectedTag.prop('outerHTML');
      $templateSelectedTag.remove();

      const $templateNewTag = $list.find('[ms-code-select="tag-name-new"]');
      const templateNewTagHTML = $templateNewTag.prop('outerHTML');
      $templateNewTag.remove();

      function createSelectedTag(value) {
        const $newTag = $(templateSelectedTagHTML);
        $newTag.find('[ms-code-select="tag-name-selected"]').text(value);
        $newTag.find('[ms-code-select="tag-close"]').on('click', function(e) {
          e.stopPropagation();
          removeTag(value);
        });
        return $newTag;
      }

      function addTag(value) {
        if (!selectedOptions.includes(value) && options.includes(value)) {
          selectedOptions.push(value);
          $selectedWrapper.append(createSelectedTag(value));
          updateInput();
          filterOptions();
        }
      }

      function removeTag(value) {
        selectedOptions = selectedOptions.filter(option => option !== value);
        $selectedWrapper.find(`[ms-code-select="tag-name-selected"]:contains("${value}")`).closest('[ms-code-select="tag"]').remove();
        updateInput();
        if (isMulti && selectedOptions.length > 0) {
          $input.val($input.val() + ', ');
        }
        filterOptions();
      }

      function updateInput() {
        $input.val(selectedOptions.join(', '));
      }

      function toggleList(show) {
        $list.toggle(show);
      }

      function createOptionElement(value) {
        const $option = $(templateNewTagHTML);
        $option.text(value);
        $option.on('click', function() {
          selectOption(value);
        });
        return $option;
      }

      function selectOption(value) {
        if (isMulti) {
          addTag(value);
          $input.val(selectedOptions.join(', ') + (selectedOptions.length > 0 ? ', ' : ''));
          $input.focus();
        } else {
          selectedOptions = [value];
          $selectedWrapper.empty().append(createSelectedTag(value));
          updateInput();
          toggleList(false);
        }
        filterOptions();
      }

      function filterOptions() {
        const inputValue = $input.val();
        const searchTerm = isMulti ? inputValue.split(',').pop().trim() : inputValue.trim();
        let visibleOptionsCount = 0;

        $list.find('[ms-code-select="tag-name-new"]').each(function() {
          const $option = $(this);
          const optionText = $option.text().toLowerCase();
          const matches = optionText.includes(searchTerm.toLowerCase());
          const isSelected = selectedOptions.includes($option.text());
          $option.toggle(matches && !isSelected);
          if (matches && !isSelected) visibleOptionsCount++;
        });

        $emptyState.toggle(visibleOptionsCount === 0 && searchTerm !== '');
        highlightedIndex = -1;
        updateHighlight();
      }

      function cleanInput() {
        const inputValues = $input.val().split(',').map(v => v.trim()).filter(v => v);
        const validValues = inputValues.filter(v => options.includes(v));
        selectedOptions = validValues;
        $selectedWrapper.empty();
        selectedOptions.forEach(value => $selectedWrapper.append(createSelectedTag(value)));
        updateInput();
        filterOptions();
      }

      function handleInputChange() {
        const inputValue = $input.val();
        const inputValues = inputValue.split(',').map(v => v.trim());
        const lastValue = inputValues[inputValues.length - 1];

        if (inputValue.endsWith(',') || inputValue.endsWith(', ')) {
          inputValues.pop();
          const newValidValues = inputValues.filter(v => options.includes(v) && !selectedOptions.includes(v));
          newValidValues.forEach(addTag);
          $input.val(selectedOptions.join(', ') + (selectedOptions.length > 0 ? ', ' : ''));
        } else if (options.includes(lastValue) && !selectedOptions.includes(lastValue)) {
          addTag(lastValue);
          $input.val(selectedOptions.join(', ') + ', ');
        }

        filterOptions();
      }

      function initializeWithValue() {
        const initialValue = $input.val();
        if (initialValue) {
          const initialValues = initialValue.split(',').map(v => v.trim());
          initialValues.forEach(value => {
            if (options.includes(value)) {
              addTag(value);
            }
          });
          updateInput();
          filterOptions();
        }
      }

      function updateHighlight() {
        $list.find('[ms-code-select="tag-name-new"]').removeClass('highlighted').css('background-color', '');
        if (highlightedIndex >= 0) {
          $list.find('[ms-code-select="tag-name-new"]:visible').eq(highlightedIndex)
            .addClass('highlighted')
            .css('background-color', '#e0e0e0');
        }
      }

      function handleKeyDown(e) {
        const visibleOptions = $list.find('[ms-code-select="tag-name-new"]:visible');
        const optionCount = visibleOptions.length;

        switch (e.key) {
          case 'ArrowDown':
            e.preventDefault();
            highlightedIndex = (highlightedIndex + 1) % optionCount;
            updateHighlight();
            break;
          case 'ArrowUp':
            e.preventDefault();
            highlightedIndex = (highlightedIndex - 1 + optionCount) % optionCount;
            updateHighlight();
            break;
          case 'Enter':
            e.preventDefault();
            if (highlightedIndex >= 0) {
              const selectedValue = visibleOptions.eq(highlightedIndex).text();
              selectOption(selectedValue);
            }
            break;
        }
      }

      $.each(options, function(i, option) {
        $list.append(createOptionElement(option));
      });

      $input.on('focus', function() {
        toggleList(true);
        if (isMulti) {
          const currentVal = $input.val().trim();
          if (currentVal !== '' && !currentVal.endsWith(',')) {
            $input.val(currentVal + ', ');
          }
          this.selectionStart = this.selectionEnd = this.value.length;
        }
        filterOptions();
      });

      $input.on('click', function(e) {
        e.preventDefault();
        this.selectionStart = this.selectionEnd = this.value.length;
      });

      $input.on('blur', function() {
        setTimeout(function() {
          if (!$list.is(':hover')) {
            toggleList(false);
            cleanInput();
          }
        }, 100);
      });

      $input.on('input', handleInputChange);
      $input.on('keydown', handleKeyDown);

      $list.on('mouseenter', '[ms-code-select="tag-name-new"]', function() {
        $(this).css('background-color', '#e0e0e0');
      });

      $list.on('mouseleave', '[ms-code-select="tag-name-new"]', function() {
        if (!$(this).hasClass('highlighted')) {
          $(this).css('background-color', '');
        }
      });

      initializeWithValue();
      toggleList(false);
    });
  });
</script>

Création du scénario Make.com

1. Téléchargez le modèle JSON ci-dessous pour commencer.

2. Naviguez jusqu'à Make.com et créez un nouveau scénario...

3. Cliquez sur la petite boîte avec trois points, puis sur Import Blueprint...

4. Téléchargez votre fichier et voilà ! Vous êtes prêt à relier vos propres comptes.

Besoin d'aide avec ce MemberScript ?

All Memberstack customers can ask for assistance in the 2.0 Slack. Please note that these are not official features and support cannot be guaranteed.

Join the 2.0 Slack
Version notes
Attributs
Description
Attribut
Aucun élément n'a été trouvé.
Tutorial