AppAutoComplete.vue 1.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. <script setup>
  2. import { computed } from 'vue'
  3. import { Inertia } from '@inertiajs/inertia'
  4. const props = defineProps({
  5. label: {
  6. type: String,
  7. required: false,
  8. },
  9. error: {
  10. type: String,
  11. default: null,
  12. },
  13. empty: {
  14. type: Boolean,
  15. default: false,
  16. },
  17. refreshData: {
  18. type: String,
  19. required: true,
  20. },
  21. param: {
  22. type: String,
  23. required: true,
  24. },
  25. })
  26. const emit = defineEmits(['update:modelValue'])
  27. const isError = computed(() => (props.error ? true : false))
  28. const ariaDescribedbyLabel = computed(
  29. () => props.label?.toLowerCase().replace(/\s+/g, '-') + '-error'
  30. )
  31. const removeParams = (...params) => {
  32. const urlParams = new URLSearchParams(location.search)
  33. params.forEach((value) => urlParams.delete(value))
  34. history.replaceState({}, '', `${location.pathname}?${urlParams}`)
  35. }
  36. const onInput = (event) => {
  37. if (event.target.value === '') {
  38. removeParams(props.param)
  39. }
  40. emit('update:modelValue', event.target.value)
  41. }
  42. const onComplete = (event) => {
  43. Inertia.reload({
  44. data: {
  45. [props.param]: event.query,
  46. },
  47. only: [props.refreshData],
  48. })
  49. }
  50. </script>
  51. <template>
  52. <div class="field">
  53. <label>{{ label }}</label>
  54. <AutoComplete
  55. forceSelection
  56. class="w-full"
  57. inputClass="w-full"
  58. :class="{ 'p-invalid': isError }"
  59. v-bind="$attrs"
  60. @input="onInput"
  61. @item-select="$emit('update:modelValue', $event.value)"
  62. @complete="onComplete"
  63. >
  64. <template #item="slotProps">
  65. <slot name="item" :item="slotProps.item" />
  66. </template>
  67. </AutoComplete>
  68. <div class="flex flex-column">
  69. <small
  70. v-if="error"
  71. class="mt-1"
  72. :class="{
  73. 'mb-2': empty,
  74. 'p-error': isError,
  75. }"
  76. :aria-describedby="ariaDescribedbyLabel"
  77. >
  78. {{ error }}
  79. </small>
  80. <small v-if="empty" class="mt-1">
  81. <slot name="empty" />
  82. </small>
  83. </div>
  84. </div>
  85. </template>