Search Typeahead
by Dilip Bhattarai
HTML
<script src="https://unpkg.com/vue"></script>
<div id="app" class="container">
<label for="search">Search:</label>
<input
id="search"
v-model="inputValue"
type="search"
autocomplete="off"
class="form-control"
@input="onInput" />
<pre v-html="results" class="results" />
</div>
CSS
.container {
padding: 30px;
}
.results {
margin: 20px 0;
min-height: 200px;
padding: 20px;
background: #eee;
}
strong {
font-weight: bold !important;
}
Vue
new Vue({
el: "#app",
data() {
return {
inputValue: '',
items: [
{ value: 'Jon Doe' },
{ value: 'Jonathan ' },
{ value: 'Sarah Connor' },
// and so on (Value is the field to be searched).
],
results: [],
};
},
created() {
this.results = this.items;
},
methods: {
onInput() {
const value = this.inputValue;
if (!value) {
this.results = this.items;
return;
}
const escapedQuery = this.escapeRegExp(value);
const queryReg = new RegExp(escapedQuery, 'gi');
this.results = this.matchItem(this.items, queryReg)
.map(item => ({
...item,
value: this.highlight(item.value, queryReg),
}));
},
escapeHtml(text) {
return text.replace(/</g, '<').replace(/>/g, '>');
},
escapeRegExp(text) {
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
},
matchItem(items, queryReg) {
return items
.filter(i => i.value.match(queryReg) !== null)
.sort((a, b) => {
const aIndex = a.value.indexOf(a.value.match(queryReg)[0]);
const bIndex = b.value.indexOf(b.value.match(queryReg)[0]);
if (aIndex < bIndex) return -1;
if (aIndex > bIndex) return 1;
return 0;
});
},
highlight(text, queryReg) {
const escaped = this.escapeHtml(text);
return escaped.replace(queryReg, '<strong>$&</strong>');
},
},
})