Vue.js Autocomplete

by jessekinsman

HTML

<div id="compContainer">
  <autocomplete :items="testData"></autocomplete>
</div>

CSS

* {
  box-sizing: border-box;
}
.autocomplete {
    position: relative;
    width: 100%;
  }

  .autocomplete-results {
    padding: 0;
    margin: 0;
    border: 1px solid #eeeeee;
    height: 120px;
    overflow: auto;
  }
  
  .autocomplete-input {
    width: 100%;
    padding: .5em;
    font-size: 1.2em;
  }

  .autocomplete-result, .close {
    list-style: none;
    text-align: left;
    padding: 4px 2px;
    cursor: pointer;
  }

  .autocomplete-result:hover {
    background-color: #4AAE9B;
    color: white;
  }
  
  .close {
    text-decoration: underline;
    position: absolute; 
    bottom: 5px;
  }

JavaScript

Vue.component('autocomplete', {
	props: ['items'],
	methods: {
  	filter: function(e) {
      this.results = this.items.filter((item) => {
      	return item.text.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
      });
      if (this.results.length > 0) {
      	this.isOpen = true;
      }
    },
    hide: function() {
    	this.isOpen = false;
    },
    setItem: function(item) {
    	this.selected = item;
      this.search = item.text;
      this.filter();
      this.isOpen = false;
    },
    open: function() {
    	if (this.results.length > 0) {
      	this.isOpen = true;
      }
    }
  },
  data: function() {
  	return {
    	isOpen: false,
      search: '',
      results: [],
      selected: {}
    };
  },
  template: `
  <div class="autocomplete">
  <input class="autocomplete-input" type="text" v-model="search" @input="filter($event)" @click="open()" >
  	<div class="autocomplete-results-container" v-if="isOpen">
      <ul class="autocomplete-results">
        	<li v-for="(item, i) in results" @click="setItem(item)" :key="i" class="autocomplete-result">{{item.text}}</li>
          <li class="close" @click="hide()">Close</li>
       </ul>
    </div>
   </div>
  `
});

var testData = [
	{id: 1, text: "Small false 1", updatedAt: 1558729871918},
  {id: 2, text: "Small true 1", updatedAt: 1542840193473},
  {id: 3, text: "Small false 2", updatedAt: 1542841969171},
  {id: 4, text: "Small false 3", updatedAt: 1542841995792},
  {id: 5, text: "Small true 2", updatedAt: 1542841995792},
  {id: 6, text: "Small false 4", updatedAt: 1542840824567}
];
new Vue({el: '#compContainer', data:{testData: testData}});