//TODO: if autocomplete is focus and the input has not a single character still show "Bitte mindestens 3 Zeichen eingeben" //TODO: fix the fetchSuggestions function to not show a loading spinner when the input gets cleared //TODO: fix so we can use arrow keys to navigate the suggestions Vue.component('tt-autocomplete', { template: `
`, // TODO: Implement giving the option without the need of an API || need to use computed property to filter the items // TODO: Fix the weirdness with timeout and selecting the suggestion props: { value: {type: [String, Number]}, label: {type: String, required: false}, apiUrl: String, placeholder: {type: String, default: ''}, items: {type: Array, default: () => []}, sm: {type: Boolean, default: true}, row: {type: Boolean, default: false}, }, async mounted() { if (this.value && this.apiUrl) { const response = await axios.get(`${this.apiUrl}&autocomplete=1&searchedID=${this.value}`); this.displayValue = response.data[0].text; } else if (this.value) { const selectedItem = this.items.find(item => item.value === this.value); this.displayValue = selectedItem ? selectedItem.text : ''; } else { this.$emit('input', ''); this.displayValue = ''; } }, data() { return { displayingItems: [], displayValue: '', isLoading: false, showSuggestions: false, cursor: -1, fetchSuggestionsDebounceTimer: null, }; }, watch: { value(newValue) { const selectedItem = this.displayingItems.find(item => item.value === newValue); this.displayValue = selectedItem ? selectedItem.text : ''; }, apiUrl() { this.fetchSuggestions(); }, }, methods: { onInput(event) { this.displayValue = event.target.value; this.$emit('input', ''); this.fetchSuggestions(); }, onFocus() { this.showSuggestions = true; }, onBlur() { setTimeout(() => { this.showSuggestions = false; }, 200); }, fetchSuggestions() { if (this.displayValue.length < 3) { this.$set(this, 'displayingItems', []); return this.displayingItems = []; } if (!this.apiUrl) { const isNegated = this.displayValue.startsWith('!'); const substrings = (isNegated ? this.displayValue.slice(1) : this.displayValue).split(' ').map(s => s.toLowerCase()); this.displayingItems = this.items.filter(item => { let substringMatch = true; for (var k = 0, klen = substrings.length; k < klen; ++k) { if (!item.text.toLowerCase().includes(substrings[k])) { substringMatch = false; break; } } return (isNegated && !substringMatch) || (!isNegated && substringMatch); }) return } this.isLoading = true; clearTimeout(this.fetchSuggestionsDebounceTimer); console.log(this.displayValue); this.fetchSuggestionsDebounceTimer = setTimeout(() => { setTimeout(async () => { if (this.displayValue.length < 3) { this.displayingItems = []; this.isLoading = false; return; } const response = await axios.get(`${this.apiUrl}&autocomplete=1&q=${encodeURIComponent(this.displayValue)}`); if (response.data?.status === 'error') { this.displayingItems = []; } else { this.displayingItems = response.data } this.isLoading = false; this.fetchSuggestionsDebounceTimer = null; }, 100); }, 300); // Adjust the 300ms debounce time as needed }, selectSuggestion(item) { this.$emit('input', item.value); this.displayValue = item.text; this.showSuggestions = false; }, clear() { this.displayValue = ''; this.$emit('input', ''); } }, });