nuVistA/htdocs/Autocomplete.vue

105 lines
2.1 KiB
Vue
Raw Normal View History

2022-09-22 07:10:08 -04:00
<template>
<div class="autocomplete">
<input type="text" @input="option_open" v-model="xvalue" @keydown.down="option_down" @keydown.up="option_up" @keydown.enter="option_enter" />
<ul id="autocomplete-results" v-show="open" class="autocomplete-results">
<li class="loading" v-if="!items">Loading results...</li>
<li v-else v-for="(result, i) in results" :key="i" @click="option_click(result)" class="autocomplete-result" :class="{ 'is-active': i === index }">{{ result }}</li>
</ul>
</div>
</template>
<style scoped>
.autocomplete {
position: relative;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result.is-active,
.autocomplete-result:hover {
background-color: #4AAE9B;
color: white;
}
</style>
<script>
export default {
props: {
value: {
type: String,
default: ''
},
items: {
type: Array,
required: false,
default: () => [],
}
},
data() {
return {
xvalue: '',
results: [],
open: false,
index: -1,
};
},
watch: {
value(val) {
this.xvalue = val;
},
xvalue(val) {
this.$emit('update:value', val);
}
},
mounted() {
this.xvalue = this.value;
document.addEventListener('click', this.option_close)
},
destroyed() {
document.removeEventListener('click', this.option_close)
},
methods: {
option_open() {
if(this.items) {
this.results = this.items.filter((item) => item.toLowerCase().indexOf(this.xvalue.toLowerCase()) > -1);
this.open = true;
}
},
option_down() {
if(this.index < this.results.length) this.index++;
},
option_up() {
if(this.index > 0) this.index--;
},
option_enter() {
this.xvalue = this.results[this.index];
this.open = false;
this.index = -1;
},
option_click(result) {
this.xvalue = result;
this.open = false;
},
option_close(evt) {
if(!this.$el.contains(evt.target)) {
this.open = false;
this.index = -1;
}
}
}
};
</script>