| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- <!--
- Liste déroulante avec autocompletion
- @see https://vuetifyjs.com/en/components/autocompletes/#usage
- -->
- <template>
- <main>
- <v-autocomplete
- autocomplete="search"
- :value="data"
- :items="itemsToDisplayed"
- :label="$t(label)"
- item-text="itemTextDisplay"
- :item-value="itemValue"
- :no-data-text="$t('autocomplete_research')"
- :no-filter="noFilter"
- auto-select-first
- :multiple="multiple"
- :loading="isLoading"
- :return-object="returnObject"
- :search-input.sync="search"
- :prepend-icon="prependIcon"
- @input="$emit('update', $event, field)"
- >
- <template v-if="slotText" v-slot:item="data">
- <v-list-item-content v-text="data.item.slotTextDisplay"></v-list-item-content>
- </template>
- </v-autocomplete>
- </main>
- </template>
- <script lang="ts">
- import { computed, defineComponent, ComputedRef, Ref, ref, watch, onUnmounted } from '@nuxtjs/composition-api'
- import { AnyJson } from '~/types/interfaces'
- import * as _ from 'lodash'
- import {$objectProperties} from "~/services/utils/objectProperties";
- export default defineComponent({
- props: {
- label: {
- type: String,
- required: false,
- default: null
- },
- field: {
- type: String,
- required: false,
- default: null
- },
- data: {
- type: [String, Number, Object],
- required: false,
- default: null
- },
- items: {
- type: Array,
- required: false,
- default: () => []
- },
- readonly: {
- type: Boolean,
- required: false
- },
- itemValue: {
- type: String,
- default: 'id'
- },
- itemText: {
- type: Array,
- required: true
- },
- slotText: {
- type: Array,
- required: false,
- default: null
- },
- returnObject: {
- type: Boolean,
- default: false
- },
- multiple: {
- type: Boolean,
- default: false
- },
- isLoading: {
- type: Boolean,
- default: false
- },
- noFilter: {
- type: Boolean,
- default: false
- },
- prependIcon: {
- type: String
- },
- },
- setup (props, { emit }) {
- const search:Ref<string|null> = ref(null)
- // On reconstruit les items à afficher car le text de l'Item doit être construit par rapport au itemText passé en props
- const itemsToDisplayed: ComputedRef<Array<AnyJson>> = computed(() => {
- return props.items.map((item: any) => {
- const slotTextDisplay: Array<string> = []
- const itemTextDisplay: Array<string> = []
- if(item){
- item = $objectProperties.cloneAndFlatten(item)
- //Si on souhaite avoir un texte différent dans les propositions que dans la sélection finale de select
- if(props.slotText){
- for (const text of props.slotText) {
- slotTextDisplay.push(item[text as string])
- }
- }
- for (const text of props.itemText) {
- itemTextDisplay.push(item[text as string])
- }
- }
- //On reconstruit l'objet
- return Object.assign({}, item, { itemTextDisplay: itemTextDisplay.join(' '), slotTextDisplay: slotTextDisplay.join(' ') })
- })
- })
- const unwatch = watch(search, _.debounce(async (newResearch, oldResearch) => {
- if(newResearch !== oldResearch && oldResearch !== null)
- emit('research', newResearch)
- }, 500))
- onUnmounted(() => {
- unwatch()
- })
- return {
- label_field: props.label ?? props.field,
- itemsToDisplayed,
- search
- }
- }
- })
- </script>
|