AppAutoComplete.vue 1.9KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <script setup>
  2. import { computed, onMounted } 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. })
  22. const emit = defineEmits(['update:modelValue'])
  23. const isError = computed(() => (props.error ? true : false))
  24. const ariaDescribedbyLabel = computed(
  25. () => props.label?.toLowerCase().replace(/\s+/g, '-') + '-error'
  26. )
  27. let param = props.refreshData.slice(0, -1).replace('-', '_')
  28. const removeParams = (...params) => {
  29. const urlParams = new URLSearchParams(location.search)
  30. params.forEach((value) => urlParams.delete(value))
  31. history.replaceState({}, '', `${location.pathname}?${urlParams}`)
  32. }
  33. const onInput = (event) => {
  34. if (event.target.value === '') {
  35. removeParams(param)
  36. }
  37. emit('update:modelValue', event.target.value)
  38. }
  39. const onComplete = (event) => {
  40. Inertia.reload({
  41. data: {
  42. [param]: event.query,
  43. },
  44. only: [props.refreshData],
  45. })
  46. }
  47. </script>
  48. <template>
  49. <div class="field">
  50. <label>{{ label }}</label>
  51. <AutoComplete
  52. forceSelection
  53. class="w-full"
  54. inputClass="w-full"
  55. :class="{ 'p-invalid': isError }"
  56. v-bind="$attrs"
  57. @input="onInput"
  58. @item-select="$emit('update:modelValue', $event.value)"
  59. @complete="onComplete"
  60. >
  61. <template #item="slotProps">
  62. <slot name="item" :item="slotProps.item" />
  63. </template>
  64. </AutoComplete>
  65. <div class="flex flex-column">
  66. <small
  67. v-if="error"
  68. class="mt-1"
  69. :class="{
  70. 'mb-2': empty,
  71. 'p-error': isError,
  72. }"
  73. :aria-describedby="ariaDescribedbyLabel"
  74. >
  75. {{ error }}
  76. </small>
  77. <small v-if="empty" class="mt-1">
  78. <slot name="empty" />
  79. </small>
  80. </div>
  81. </div>
  82. </template>