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, items: { type: Array, default: () => [], } }, 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 : ''; } }, 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', undefined); 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); this.fetchSuggestionsDebounceTimer = setTimeout(() => { // Simulate the API call setTimeout(async () => { const response = await axios.get(`${this.apiUrl}&autocomplete=1&q=${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; }, }, });