Skip to content
Snippets Groups Projects
Dropdown.vue 3.26 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"
Timothee P's avatar
Timothee P committed
    <div v-if="!input" class="default text">{{ selected }}</div>
    <i
      :class="['dropdown icon', { clear: clearable && selected }]"
      @click="clear"
    ></i>
    <div :class="['menu', { 'visible transition': isOpen }]">
      <div
        v-for="(option, index) in processedOptions || ['No results found.']"
        @click="select(index)"
        :key="option + index"
        :class="[
          processedOptions ? 'item' : 'message',
          { 'active selected': option === selected },
        ]"
      >
        {{ option }}
      </div>
  props: [
    "options",
    "selected",
    "disabled",
    "search",
    "placeholder",
    "clearable",
  ],
    processedOptions: function () {
      //* si un objet {name, value}
Timothee P's avatar
Timothee P committed
        el.constructor === Object ? el.name : el
      );
      if (this.search && this.input !== "") {
        options = this.searchOptions(options);
      }
      return options.length > 0 ? options : null;
    },

    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);
      this.$emit("update:selection", this.options[index]);
      this.input = "";
    },
Timothee P's avatar
Timothee P committed

    searchOptions(options) {
      return options.filter((el) =>
        el.toLowerCase().includes(this.input.toLowerCase())
      );
    },
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;
}
</style>