AutocompleteWithAPI.vue 2.8 KB

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