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, '&lt;').replace(/>/g, '&gt;');
    },

    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>');
    },
  },
})