Skip to content
Snippets Groups Projects
DropdownMenuItem.vue 4.67 KiB
Newer Older
Florent Lavelle's avatar
dev
Florent Lavelle committed
<template>
  <Multiselect
Timothee P's avatar
Timothee P committed
    v-model="selection"
Timothee P's avatar
Timothee P committed
    :options="options"
    :allow-empty="true"
    track-by="label"
    label="label"
    :reset-after="false"
    select-label=""
    selected-label=""
    deselect-label=""
    :searchable="false"
    :placeholder="placeholder"
    :clear-on-select="false"
    :preserve-search="true"
Timothee P's avatar
Timothee P committed
    @select="select"
Timothee P's avatar
Timothee P committed
    @close="close"
    <template
      slot="option"
      slot-scope="props"
    >
      <span :title="props.option.label">{{ props.option.label }}</span>
    </template>
Timothee P's avatar
Timothee P committed
    <template
      v-if="multiple"
      slot="selection"
      slot-scope="{ values }"
    >
      <span
        v-if="values && values.length > 1"
        class="multiselect__single"
      >
        {{ values.length }} options sélectionnées
      </span>
Timothee P's avatar
Timothee P committed
      <span
        v-else
        class="multiselect__single"
      >{{ currentSelectionLabel || selection.label }}</span>
Florent Lavelle's avatar
dev
Florent Lavelle committed
</template>

<script>
import Multiselect from 'vue-multiselect';

export default {
  name: 'DropdownMenuItem',

Timothee P's avatar
Timothee P committed
  components: {
    Multiselect
  },
Florent Lavelle's avatar
dev
Florent Lavelle committed

Timothee P's avatar
Timothee P committed
  props: {
    placeholder: {
      type: String,
      default: 'Sélectionnez une valeur'
    },
    options: {
      type: Array,
      default: () => {
        return [];
      }
    multiple: {
      type: Boolean,
      default: false
    },
    currentSelection: {
      type: [String, Array, Boolean],
      default: null,
    },
    defaultFilter: {
      type: [String, Array, Boolean],
      default: null,
Timothee P's avatar
Timothee P committed
    }
  },
Florent Lavelle's avatar
dev
Florent Lavelle committed

  data() {
    return {
      selection: null,
Timothee P's avatar
Timothee P committed
    };
Florent Lavelle's avatar
dev
Florent Lavelle committed
  },

  computed: {
    /**
     * Get the label of an option to work with project attributes options as JSON
     */
    currentSelectionLabel() {
      const option = this.options.find(opt => opt.value === this.currentSelection);
      return option ? option.label : '';
    }
  },

Timothee P's avatar
Timothee P committed
  watch: {
    selection: {
      deep: true,
      handler(newValue) {
        if (!newValue) {
          this.selection = this.options[0];
          this.$emit('filter', this.selection);
        }
      }
    currentSelection(newValue) {
      this.updateSelection(newValue);
Timothee P's avatar
Timothee P committed
  },
Timothee P's avatar
Timothee P committed
  created() {
    if (this.currentSelection !== null) {
      this.selection = this.options.find(opt => opt.value === this.currentSelection);
    } else {
      this.selection = this.options[0];
Timothee P's avatar
Timothee P committed
  },
Florent Lavelle's avatar
dev
Florent Lavelle committed
  methods: {
    select(e) {
      this.$emit('filter', e);
Florent Lavelle's avatar
dev
Florent Lavelle committed
    },
Florent Lavelle's avatar
dev
Florent Lavelle committed
    close() {
      this.$emit('close', this.selection);
    },
    /**
     * Normalizes the input value(s) to an array of strings.
     * This handles both single string inputs and comma-separated strings, converting them into an array.
     *
     * @param {String|Array} value - The input value to normalize, can be a string or an array of strings.
     * @return {Array} An array of strings representing the input values.
     */
    normalizeValues(value) {
      // If the value is a string and contains commas, split it into an array; otherwise, wrap it in an array.
      return typeof value === 'string' ? (value.includes(',') ? value.split(',') : [value]) : value;
    },

    /**
     * Updates the current selection based on new value, ensuring compatibility with multiselect.
     * This method processes the new selection value, accommodating both single and multiple selections,
     * and updates the internal `selection` state with the corresponding option objects from `options`.
     *
     * @param {String|Array} value - The new selection value(s), can be a string or an array of strings.
     */
    // Check if the component is in multiple selection mode and the new value is provided.
    updateSelection(value) {
      if (this.multiple && value) {
        // Normalize the value to an array format, accommodating both single and comma-separated values.
        const normalizedValues = this.normalizeValues(value);

        // Map each value to its corresponding option object based on the 'value' field.
        this.selection = normalizedValues.map(value => 
          this.options.find(option => option.value === value)
        );
      } else {
        // For single selection mode or null value, find the option object that matches the value.
        this.selection = this.options.find(option => option.value === value);
      }
Florent Lavelle's avatar
dev
Florent Lavelle committed
    }
  }
Timothee P's avatar
Timothee P committed
};
Florent Lavelle's avatar
dev
Florent Lavelle committed
</script>

<style>
#filters-container .multiple .multiselect__option--selected:not(:hover) {
  background-color: #e8e8e8 !important;
}
#filters-container .multiselect--disabled .multiselect__select {
  background: 0, 0 !important;
}