AppDropdown.vue 1.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <script setup>
  2. import { computed } from 'vue'
  3. const props = defineProps({
  4. optionLabel: {
  5. type: String,
  6. default: 'label',
  7. },
  8. optionValue: {
  9. type: String,
  10. default: 'value',
  11. },
  12. optionDisabled: {
  13. type: String,
  14. default: 'disabled',
  15. },
  16. options: {
  17. type: Array,
  18. required: true,
  19. },
  20. label: {
  21. type: String,
  22. required: false,
  23. },
  24. placeholder: {
  25. type: String,
  26. required: true,
  27. },
  28. error: {
  29. type: String,
  30. default: null,
  31. },
  32. modelValue: null,
  33. })
  34. defineEmits(['update:modelValue'])
  35. const isError = computed(() => (props.error ? true : false))
  36. const forLabel = computed(() => (props.label ? props.label.toLowerCase().replace(/\s+/g, '-') : null))
  37. const ariaDescribedbyLabel = computed(() =>
  38. props.label ? props.label.toLowerCase().replace(/\s+/g, '-') + '-help' : null
  39. )
  40. const selectedDropdownLabel = (value) => {
  41. const result = props.options.find((option) => option[props.optionValue] == value)
  42. if (result) {
  43. return result[props.optionLabel]
  44. }
  45. }
  46. </script>
  47. <template>
  48. <label v-if="label" :for="forLabel">{{ label }}</label>
  49. <Dropdown
  50. class="w-full mt-2"
  51. :class="{ 'p-invalid': isError }"
  52. :id="forLabel"
  53. :aria-describedby="ariaDescribedbyLabel"
  54. :option-disabled="optionDisabled"
  55. :option-label="optionLabel"
  56. :option-value="optionValue"
  57. :placeholder="placeholder"
  58. :options="options"
  59. :model-value="modelValue"
  60. @change="$emit('update:modelValue', $event.value)"
  61. >
  62. <template #value="slotProps">
  63. <div v-if="slotProps.value">
  64. {{ selectedDropdownLabel(slotProps.value) }}
  65. </div>
  66. <div v-else>
  67. {{ slotProps.placeholder }}
  68. </div>
  69. </template>
  70. <template #option="{ option, index }">
  71. <slot name="option" :option="option" :index="index" />
  72. </template>
  73. </Dropdown>
  74. <small v-if="error" :id="ariaDescribedbyLabel" :class="{ 'p-error': isError }">
  75. {{ error }}
  76. </small>
  77. </template>