Autocomplete.vue 3.5 KB

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