Skip to content

Instantly share code, notes, and snippets.

@pushrbx
Created October 2, 2019 09:59
Show Gist options
  • Save pushrbx/a3a57ff67862d7b08724b9ea0a5c1692 to your computer and use it in GitHub Desktop.
Save pushrbx/a3a57ff67862d7b08724b9ea0a5c1692 to your computer and use it in GitHub Desktop.
<template>
<div v-on-clickaway="clickAway">
<input type="text" class="form-control"
:value="value"
@focus="onFocus"
@input="onInput"
@keydown.enter.prevent="enter"
@keydown.down.prevent="down"
@keydown.up.prevent="up"
@keydown.tab="clickAway" />
<div v-if="open && (matches.length || dirty)" class="suggestions">
<div v-if="matches.length">
<span class="suggestion"
v-for="(suggestion, index) in matches"
:class="{'active': isActive(index)}"
@click.stop="click(index)">
{{ suggestion.text }}
</span>
</div>
<p v-if="dirty && !matches.length">No matches found, please search again.</p>
</div>
</div>
</template>
<script>
import { mixin as clickaway } from 'vue-clickaway';
export default {
props: ['items', 'value'],
mixins: [clickaway],
data () {
return {
current: -1,
open: false,
dirty: false
}
},
computed: {
matches() {
if (this.value.length === 0) {
return this.items.slice(0, 9);
} else {
return this.items.filter((item) => {
return item.text.toLowerCase().indexOf(this.value.toLowerCase()) >= 0 && item.text.toLowerCase() !== this.value.toLowerCase();
});
}
}
},
methods: {
onFocus() {
this.open = true;
},
clickAway() {
this.open = false;
var filtered = this.items.filter((item) => {
return item.text.toLowerCase() === this.value.toLowerCase();
});
if (filtered.length !== 1) {
this.$emit('input', '');
}
},
onInput(ev) {
this.dirty = true;
this.$emit('input', ev.target.value);
this.open = true;
},
enter() {
this.$emit('input', this.matches[this.current].text);
this.current = -1;
this.open = false;
this.dirty = false;
},
up() {
if (this.current >= 0)
this.current--;
},
down() {
if (this.current < this.matches.length - 1)
this.current++;
},
isActive(index) {
return index === this.current;
},
click(index) {
this.$emit('input', this.matches[index].text);
this.current = -1;
this.open = false;
this.dirty = false;
}
}
}
</script>
<style scoped>
* {
box-sizing: border-box;
}
.suggestions {
margin-top: -1px;
border: 1px solid #8ea3b0;
background: white;
position: absolute;
left: 15px;
right: 15px;
z-index: 1;
}
.suggestions p {
color: #FF6666;
margin: 0;
padding: 10px;
}
.suggestions span {
display: block;
padding: 6px 12px;
border-bottom: 1px solid #d6dde2;
cursor: pointer;
color: #95989b;
}
.suggestions span:hover {
background: #d6dde2;
color: #575d62;
}
.suggestions span.active {
background: #d6dde2;
color: #575d62;
}
.suggestions span:last-of-type {
border-bottom: none;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment