Autocomplete.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <!--
  2. Liste déroulante avec autocompletion
  3. @see https://vuetifyjs.com/en/components/autocompletes/#usage
  4. -->
  5. <template>
  6. <main>
  7. <v-autocomplete
  8. autocomplete="search"
  9. :value="data"
  10. :items="itemsToDisplayed"
  11. :label="$t(label)"
  12. item-text="itemTextDisplay"
  13. :item-value="itemValue"
  14. :no-data-text="$t('autocomplete_research')"
  15. :no-filter="noFilter"
  16. auto-select-first
  17. :multiple="multiple"
  18. :loading="isLoading"
  19. :return-object="returnObject"
  20. :search-input.sync="search"
  21. :prepend-icon="prependIcon"
  22. :error="error"
  23. @input="onChange($event)"
  24. >
  25. <template v-if="slotText" v-slot:item="data">
  26. <v-list-item-content v-text="data.item.slotTextDisplay"></v-list-item-content>
  27. </template>
  28. </v-autocomplete>
  29. </main>
  30. </template>
  31. <script lang="ts">
  32. import { computed, defineComponent, ComputedRef, Ref, ref, watch, onUnmounted } from '@nuxtjs/composition-api'
  33. import { AnyJson } from '~/types/interfaces'
  34. import * as _ from 'lodash'
  35. import {$objectProperties} from "~/services/utils/objectProperties";
  36. import {$useError} from "~/use/form/useError";
  37. export default defineComponent({
  38. props: {
  39. label: {
  40. type: String,
  41. required: false,
  42. default: null
  43. },
  44. field: {
  45. type: String,
  46. required: false,
  47. default: null
  48. },
  49. data: {
  50. type: [String, Number, Object],
  51. required: false,
  52. default: null
  53. },
  54. items: {
  55. type: Array,
  56. required: false,
  57. default: () => []
  58. },
  59. readonly: {
  60. type: Boolean,
  61. required: false
  62. },
  63. itemValue: {
  64. type: String,
  65. default: 'id'
  66. },
  67. itemText: {
  68. type: Array,
  69. required: true
  70. },
  71. slotText: {
  72. type: Array,
  73. required: false,
  74. default: null
  75. },
  76. returnObject: {
  77. type: Boolean,
  78. default: false
  79. },
  80. multiple: {
  81. type: Boolean,
  82. default: false
  83. },
  84. isLoading: {
  85. type: Boolean,
  86. default: false
  87. },
  88. noFilter: {
  89. type: Boolean,
  90. default: false
  91. },
  92. prependIcon: {
  93. type: String
  94. },
  95. },
  96. setup (props, { emit }) {
  97. const search:Ref<string|null> = ref(null)
  98. const {error, onChange} = $useError(props.field, emit)
  99. // On reconstruit les items à afficher car le text de l'Item doit être construit par rapport au itemText passé en props
  100. const itemsToDisplayed: ComputedRef<Array<AnyJson>> = computed(() => {
  101. return props.items.map((item: any) => {
  102. const slotTextDisplay: Array<string> = []
  103. const itemTextDisplay: Array<string> = []
  104. if(item){
  105. item = $objectProperties.cloneAndFlatten(item)
  106. //Si on souhaite avoir un texte différent dans les propositions que dans la sélection finale de select
  107. if(props.slotText){
  108. for (const text of props.slotText) {
  109. slotTextDisplay.push(item[text as string])
  110. }
  111. }
  112. for (const text of props.itemText) {
  113. itemTextDisplay.push(item[text as string])
  114. }
  115. }
  116. //On reconstruit l'objet
  117. return Object.assign({}, item, { itemTextDisplay: itemTextDisplay.join(' '), slotTextDisplay: slotTextDisplay.join(' ') })
  118. })
  119. })
  120. const unwatch = watch(search, _.debounce(async (newResearch, oldResearch) => {
  121. if(newResearch !== oldResearch && oldResearch !== null)
  122. emit('research', newResearch)
  123. }, 500))
  124. onUnmounted(() => {
  125. unwatch()
  126. })
  127. return {
  128. label_field: props.label ?? props.field,
  129. itemsToDisplayed,
  130. search,
  131. error,
  132. onChange
  133. }
  134. }
  135. })
  136. </script>