Skip to content
Snippets Groups Projects
Dropdown.vue 4.07 KiB
Newer Older
    :id="`custom-dropdown${identifier}`"
    :class="[
      'ui search selection dropdown',
      { 'active visible': isOpen },
      { disabled },
    ]"
    @click="toggleDropdown"
  >
    <input
      v-if="search"
Timothee P's avatar
Timothee P committed
      v-model="input"
      @input="isOpen = true"
Timothee P's avatar
Timothee P committed
      v-on:keyup.enter="select(0)"
      v-on:keyup.esc="toggleDropdown(false)"
Timothee P's avatar
Timothee P committed
      :placeholder="placehold"
      ref="input"
    <div v-if="!input" class="default text">
      <!-- {{ selected }} -->
      <div v-if="Array.isArray(selected)">
        <span v-if="selected[0]"> {{ selected[0] }} - </span>
        <span class="italic">{{ selected[1] }}</span>
      </div>
      <div v-else>{{ selected }}</div>
    <i
      :class="['dropdown icon', { clear: clearable && selected }]"
      @click="clear"
    ></i>
    <div :class="['menu', { 'visible transition': isOpen }]">
      <div
        v-for="(option, index) in filteredOptions || ['No results found.']"
        @click="select(index)"
        :key="option + index"
        :class="[
          filteredOptions ? 'item' : 'message',
          { 'active selected': option.name === selected },
        <div v-if="option.name && Array.isArray(option.name)">
          <span v-if="option.name[0]"> {{ option.name[0] }} - </span>
          <span class="italic">{{ option.name[1] }}</span>
        </div>
        <span v-else-if="option.name">
          {{ option.name }}
        </span>
        <span v-else>
  props: [
    "options",
    "selected",
    "disabled",
    "search",
    "placeholder",
    "clearable",
  ],
    filteredOptions: function () {
      let options = this.options;
        options = this.options.filter(this.matchInput);

    placehold() {
      return this.input ? "" : this.placeholder;
    },
      identifier: 0,
Timothee P's avatar
Timothee P committed
    toggleDropdown(val) {
      if (this.isOpen) {
        this.input = ""; // * clear input field when closing dropdown
Timothee P's avatar
Timothee P committed
      } else if (this.search) {
        //* focus on input if is a search dropdown
Timothee P's avatar
Timothee P committed
        this.$refs.input.focus({
          preventScroll: true,
        });
      } else if (this.clearable && val.target && this.selected) {
        this.clear(); //* clear selected and input
Timothee P's avatar
Timothee P committed
      }
      this.isOpen = typeof val === "boolean" ? val : !this.isOpen;
Timothee P's avatar
Timothee P committed

Timothee P's avatar
Timothee P committed
      // * toggle dropdown is called several time, timeout delay this function to be the last
Timothee P's avatar
Timothee P committed
        this.isOpen = false;
      }, 0);
Timothee P's avatar
Timothee P committed
      if (index) this.$emit("update:selection", this.filteredOptions[index]);
Timothee P's avatar
Timothee P committed

    matchInput(el) {
      let match;
      if (el.name && Array.isArray(el.name)) {
        match =
          el.name[0].toLowerCase().includes(this.input.toLowerCase()) ||
          el.name[1].toLowerCase().includes(this.input.toLowerCase());
      } else {
        match = el.name
          ? el.name.toLowerCase().includes(this.input.toLowerCase())
          : el.toLowerCase().includes(this.input.toLowerCase());
      }
      return match;
Timothee P's avatar
Timothee P committed

    clear() {
      if (this.clearable) {
        this.input = "";
        this.$emit("update:selection", "");
        if (this.isOpen) this.toggleDropdown(false);
      }
    },

      if (!e.target.closest(`#custom-dropdown${this.identifier}`))
Timothee P's avatar
Timothee P committed
        this.toggleDropdown(false);
    this.identifier = Math.floor(Math.random() * 10000);
    window.addEventListener("mousedown", this.clickOutsideDropdown);
  },

  beforeDestroy() {
    window.removeEventListener("mousedown", this.clickOutsideDropdown);
  },
};
</script>

<style scoped>
.ui.selection.dropdown .menu > .item {
  white-space: nowrap;
}
.italic {
  font-style: italic;
}