AppDropdown.vue 2.1KB

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