|
@@ -7,21 +7,34 @@ Liste déroulante avec autocompletion
|
|
|
<template>
|
|
<template>
|
|
|
<main>
|
|
<main>
|
|
|
<v-autocomplete
|
|
<v-autocomplete
|
|
|
|
|
+ autocomplete="search"
|
|
|
|
|
+ :value="data"
|
|
|
:items="itemsToDisplayed"
|
|
:items="itemsToDisplayed"
|
|
|
:label="$t(label)"
|
|
:label="$t(label)"
|
|
|
- item-text="textDisplay"
|
|
|
|
|
|
|
+ item-text="itemTextDisplay"
|
|
|
:item-value="itemValue"
|
|
:item-value="itemValue"
|
|
|
|
|
+ :no-data-text="$t('autocomplete_research')"
|
|
|
|
|
+ :no-filter="noFilter"
|
|
|
|
|
+ auto-select-first
|
|
|
:multiple="multiple"
|
|
:multiple="multiple"
|
|
|
:loading="isLoading"
|
|
:loading="isLoading"
|
|
|
:return-object="returnObject"
|
|
:return-object="returnObject"
|
|
|
- @change="$emit('update', $event, field)"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ :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>
|
|
</main>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
<script lang="ts">
|
|
|
-import { computed, defineComponent, ComputedRef } from '@nuxtjs/composition-api'
|
|
|
|
|
|
|
+import { computed, defineComponent, ComputedRef, Ref, ref, watch, onUnmounted } from '@nuxtjs/composition-api'
|
|
|
import { AnyJson } from '~/types/interfaces'
|
|
import { AnyJson } from '~/types/interfaces'
|
|
|
|
|
+import * as _ from 'lodash'
|
|
|
|
|
+import {$objectProperties} from "~/services/utils/objectProperties";
|
|
|
|
|
|
|
|
export default defineComponent({
|
|
export default defineComponent({
|
|
|
props: {
|
|
props: {
|
|
@@ -36,7 +49,7 @@ export default defineComponent({
|
|
|
default: null
|
|
default: null
|
|
|
},
|
|
},
|
|
|
data: {
|
|
data: {
|
|
|
- type: String,
|
|
|
|
|
|
|
+ type: [String, Number, Object],
|
|
|
required: false,
|
|
required: false,
|
|
|
default: null
|
|
default: null
|
|
|
},
|
|
},
|
|
@@ -57,6 +70,11 @@ export default defineComponent({
|
|
|
type: Array,
|
|
type: Array,
|
|
|
required: true
|
|
required: true
|
|
|
},
|
|
},
|
|
|
|
|
+ slotText: {
|
|
|
|
|
+ type: Array,
|
|
|
|
|
+ required: false,
|
|
|
|
|
+ default: null
|
|
|
|
|
+ },
|
|
|
returnObject: {
|
|
returnObject: {
|
|
|
type: Boolean,
|
|
type: Boolean,
|
|
|
default: false
|
|
default: false
|
|
@@ -68,28 +86,58 @@ export default defineComponent({
|
|
|
isLoading: {
|
|
isLoading: {
|
|
|
type: Boolean,
|
|
type: Boolean,
|
|
|
default: false
|
|
default: false
|
|
|
- }
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ noFilter: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false
|
|
|
|
|
+ },
|
|
|
|
|
+ prependIcon: {
|
|
|
|
|
+ type: String
|
|
|
|
|
+ },
|
|
|
},
|
|
},
|
|
|
- setup (props) {
|
|
|
|
|
|
|
+ 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
|
|
// 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(() => {
|
|
const itemsToDisplayed: ComputedRef<Array<AnyJson>> = computed(() => {
|
|
|
return props.items.map((item: any) => {
|
|
return props.items.map((item: any) => {
|
|
|
- const textDisplay: Array<string> = []
|
|
|
|
|
- for (const text of props.itemText) {
|
|
|
|
|
- textDisplay.push(item[text as string])
|
|
|
|
|
|
|
+ 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])
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- return Object.assign({}, item, { textDisplay: textDisplay.join(' ') })
|
|
|
|
|
|
|
+
|
|
|
|
|
+ //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 {
|
|
return {
|
|
|
label_field: props.label ?? props.field,
|
|
label_field: props.label ?? props.field,
|
|
|
- itemsToDisplayed
|
|
|
|
|
|
|
+ itemsToDisplayed,
|
|
|
|
|
+ search
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
</script>
|
|
</script>
|
|
|
-
|
|
|
|
|
-<style scoped>
|
|
|
|
|
-
|
|
|
|
|
-</style>
|
|
|