AutocompleteWithAPI.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <!--
  2. Liste déroulante avec autocompletion (les données sont issues
  3. d'une api)
  4. @see https://vuetifyjs.com/en/components/autocompletes/#usage
  5. -->
  6. <template>
  7. <main>
  8. <UiInputAutocomplete
  9. :field="field"
  10. :label="label"
  11. :data="remoteData ? remoteData : data"
  12. :items="items"
  13. :is-loading="isLoading"
  14. :item-text="itemText"
  15. :slot-text="slotText"
  16. :item-value="itemValue"
  17. :multiple="multiple"
  18. :chips="chips"
  19. prepend-icon="mdi-magnify"
  20. :return-object="returnObject"
  21. :no-filter="noFilter"
  22. @research="search"
  23. @update="$emit('update', $event, field)"
  24. />
  25. </main>
  26. </template>
  27. <script setup lang="ts">
  28. import { ref, toRefs, watch } from 'vue'
  29. import type { Ref } from 'vue'
  30. import { useFetch } from '#app'
  31. import UrlUtils from '~/services/utils/urlUtils'
  32. const props = defineProps({
  33. label: {
  34. type: String,
  35. required: false,
  36. default: null,
  37. },
  38. field: {
  39. type: String,
  40. required: false,
  41. default: null,
  42. },
  43. searchFunction: {
  44. type: Function as PropType<
  45. (research: string, field?: string) => Promise<Array<unknown>>
  46. >,
  47. required: true,
  48. },
  49. data: {
  50. type: [String, Number, Object, Array],
  51. required: false,
  52. default: null,
  53. },
  54. remoteUri: {
  55. type: [Array],
  56. required: false,
  57. default: null,
  58. },
  59. remoteUrl: {
  60. type: String,
  61. required: false,
  62. default: null,
  63. },
  64. readonly: {
  65. type: Boolean,
  66. required: false,
  67. },
  68. itemValue: {
  69. type: String,
  70. default: 'id',
  71. },
  72. itemTitle: {
  73. type: Array,
  74. required: true,
  75. },
  76. slotText: {
  77. type: Array,
  78. required: false,
  79. default: () => [],
  80. },
  81. returnObject: {
  82. type: Boolean,
  83. default: false,
  84. },
  85. noFilter: {
  86. type: Boolean,
  87. default: false,
  88. },
  89. multiple: {
  90. type: Boolean,
  91. default: false,
  92. },
  93. chips: {
  94. type: Boolean,
  95. default: false,
  96. },
  97. })
  98. const emit = defineEmits(['update'])
  99. const { data } = toRefs(props)
  100. const items = ref([])
  101. const remoteData: Ref<Array<string> | null> = ref(null)
  102. const isLoading = ref(false)
  103. if (props.data) {
  104. items.value = props.multiple ? (data.value ?? []) : [data.value]
  105. } else if (props.remoteUri) {
  106. const ids: Array<string | number> = []
  107. for (const uri of props.remoteUri) {
  108. ids.push(UrlUtils.extractIdFromUri(uri as string))
  109. }
  110. const options: FetchOptions = {
  111. method: 'GET',
  112. query: { key: 'id', value: ids.join(',') },
  113. }
  114. useFetch(async () => {
  115. isLoading.value = true
  116. const r: { data: Array<string> } = await $fetch(props.remoteUrl, options)
  117. isLoading.value = false
  118. remoteData.value = r.data
  119. items.value = r.data
  120. })
  121. }
  122. const search = async (research: string) => {
  123. isLoading.value = true
  124. const func = props.searchFunction
  125. items.value = items.value.concat(await func(research, props.field))
  126. isLoading.value = false
  127. }
  128. const unwatch = watch(data, (d) => {
  129. items.value = props.multiple ? d : [d]
  130. })
  131. onUnmounted(() => {
  132. unwatch()
  133. })
  134. </script>