I'm trying to make a simple dropdown search select list. I'd like to hide the name list by clicking outside of it. And the issue is that when I click outside the list of search items by using @blur directive the appropriate list item doesn't fill the input field. It's assumingly because of the @click="selectCategory(category)" is triggered later than @blur="isVisible = false" in the template.
<template>
<div сlass="search-bar" :style="{'position' : (isVisible) ? 'absolute' : 'fixed'}">
<input
type="text"
v-model="input"
@focus="isVisible = true"
// @blur="isVisible = false" doesn't work as required
/>
<div class="search-bar-options" v-if="isVisible">
<div v-for="category in filteredUser" :key="category.id" @click="selectCategory(category)">
<p>{{ category.name }}</p>
</div>
<div v-if="filteredUser.length === 0">
<p>No results found!</p>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
input: "",
selectedItem: null,
categoriesDynamic: [],
isVisible: false,
};
},
mounted() {
fetch("https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((json) => {
this.categoriesDynamic = json;
});
},
filteredUser() {
const query = this.input.toLowerCase();
if (this.input === "") {
return this.categoriesDynamic;
} else {
return this.categoriesDynamic.filter(category => {
return category.name.toLowerCase().includes(query);
});
}
},
},
methods: {
selectCategory(category) {
this.input = category.name;
this.isVisible = false;
},
},
};
</script>
<style scoped>
.pointer {
cursor: pointer;
}
.show {
visibility: show;
}
.hide {
visibility: hidden;
}
</style>
One solution could be to detect the clicked element. If the clicked element is not an input or a category element, then the dropdown can be closed.
Here is a working demo in which I gave a class "category" to each list item for element detecting purposes.