IMG-LOGO

How to create autocomplete textbox in Vue.js?

andy - 14 Jan, 2019 10495 Views 1 Comment

In this tutorial you will learn how to create a Vue.js autocomplete textbox component. So what is an autocomplete textbox component? It means a textbox that will display a list of items that matched with the keyword you enter in the input textbox. We are going to create the autocomplete when a user has entered more than 2 characters. Once the keyword has been entered, we will perform a query to a free API site to return a list of matched records based on keyword entered by a user. In this simple example tutorial, we are going to query country names. We will use Axios library to consume the JSON result.

The first thing we have to do is to import the Vue.js library. I am going to use a script tag version on this tutorial.

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

We also need to include the axios library script as below.

<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

The next step is to front end code first. We will create a div block with id assigned and create our auto complete Vue.js component.

<div id="app">
	<autocomplete 
		:place-holder-text="placeHolderInputText"
		:result-items="autoCompleteResult"
		:on-key-up="onKeyUpAutoCompleteEvent"
		:on-selected="onSelectedAutoCompleteEvent"
		:auto-complete-progress="autoCompleteProgress"
		:item-text="autoCompleteText"
		:item-id="autoCompleteFieldId">
	</autocomplete>
</div>

From above code, you can see we are going to create 7 properties which are described as below. Please note when we declare the variable in Vue.js, it will use the camelCased format and when you use it in the DOM templates (HTML), it needs to use kebab-case(hyphen-delimited). For example: if you declare placeHolderText, the kebab-case prop will be place-holder-text.

  • 1. placeHolderText

    This property is pretty straight forward, it will be used to display temporary place holder in the input.

  • 2. resultItems

    This property will be used to hold the result data retrieved from JSON. This property will be in an Array type.

  • 3. onKeyUp

    This is a function type. It will trigger this event for key up event when a user types in letters.

  • 4. onSelected

    This is a function type as well. It will trigger this event when a user select a particular item from the item result.

  • 5. autoCompleteProgress

    This will be a boolean type. It is used to flag or indicate ifconsuming JOSN data is in progress.

  • 6. itemText

    This will used to set the selected item text.

  • 7. itemId

    This will used to set the selected item id value.

So let's get started to write the Vue.js component. We need to use the keyword function Vue.component to create our component. Below is the full code of our component.

var autoCompleteComponent = Vue.component('autocomplete', {
    props: {
        placeHolderText: String,
        onKeyUp: Function,
        onSelected: Function,
        resultItems: Array,
        autoCompleteProgress: Boolean,
        itemText: String,
        itemId: String
    },

    data() {
        return {
            keywordSearch: ''
        }
    },

    template: `
		<div class="autocomplete">
			<input type="text" :placeholder="placeHolderText" v-model="keywordSearch" class="form-textinput" :class="{ 'loading-circle' : (keywordSearch.length > 2), 'hide-loading-circle': resultItems.length > 0 || resultItems.length == 0 && !autoCompleteProgress  }" @keyup="!autoCompleteProgress ? onKeyUp(keywordSearch) : ''"/>
			<ul class="autocomplete-results" v-if="resultItems.length > 0">
				<li class="autocomplete-result" v-for="(item,i) in resultItems" :key="i" @click="keywordSearch='';onSelected(item[itemId], item[itemText])">
					{{ item[itemText] }}
				</li>
			</ul>
		</div>
	`
});

As you can see we divide the component into three sections. The first section is the component properties section. We have four different type properties in our section which are String, Function, Array, and Boolean types. The second section, is the data or variable section, which is used to hold or store our data. One thing to remember, when using data in Component, you need to return it as a function otherwise it will not work. We have a variable called keywordSearch. This variable will be used as a model for our input value text. The last section is the template itself. There are some logic or condition applied into the template. The conditions are explained below.

  • The first condition is applying the CSS class. If you see on the keyword :class. We place a condition where if the input entered by a user has more than 2 characters, we want to add a loading-circle CSS class into our input. This CSS class will place a loading circle gif to let the user knows there is progress retrieving a JSON data result. Also, there is an extra condition that will be used to hide this loading circle gif if the JSON result has records returned or no data returned and a flag of autoCompleteProgress is equal to false which means has already completed consumed the data. There is an event onKeyUp attached as well on the input field. This event attached will be used to perform a query to get the country result data.
  • The second condition applies to the result div. It will construct a ul li list items if the JSON result has returned records. It will use the v-for directive to perform a for loop to display the list items. An event has been attached to the list item which is used when a user clicks into one of this list item. It will basically set the model or input entered by a user to empty value and calls a method named onSelected. In this example, onSelected method will just alert a user on what item text and id the user has selected.

In order to use the component, we need to declare data variables and methods that are needed by the autocomplete component. Below is the javascript code to initiate our Vue.js component.

var app = new Vue({
	el: '#app',
	data: {
		placeHolderInputText: 'Enter country name',
		autoCompleteResult: [],
		autoCompleteProgress: false,
		autoCompleteText: "name",
		autoCompleteFieldId: "alpha3Code"
	},
	methods: {
		onSelectedAutoCompleteEvent(id, text){
			this.autoCompleteProgress = false;
			this.autoCompleteResult = [];
			alert("You have selected " + id + ": " + text);
		},

		onKeyUpAutoCompleteEvent(keywordEntered){
			//reset
			this.autoCompleteResult = [];
			this.autoCompleteProgress = false;
			if(keywordEntered.length > 2){
				this.autoCompleteProgress = true;
				axios.get("https://restcountries.eu/rest/v2/name/" + keywordEntered)
				.then(response => {
					//because the name can contains partial name, we only include the country that contains the keyword text
					var newData = [];
					response.data.forEach(function(item, index){
						if(item.name.toLowerCase().indexOf(keywordEntered.toLowerCase()) >= 0){
							newData.push(item);
						}
					});
					this.autoCompleteResult = newData;
					this.autoCompleteProgress = false;
				})
				.catch(e => {
					this.autoCompleteProgress = false;
					this.autoCompleteResult = [];
				})
			}else{
				this.autoCompleteProgress = false;
				this.autoCompleteResult = [];
			}
		},
	}
})

As you can see, we declare all the data variables needed inside the Vue.js main data section. There are also two methods that will be used in performing a query search which is onKeyUpAutoCompleteEvent method and onSelectedAutoCompleteEvent will be used to alert the user of the selection choice. If you see on the onKeyUpAutoCompleteEvent method, It will perform a JSON consume to https://restcountries.eu api site. This api will return a list of json countries object. We are passing a keyword country name and it will return a list of matched countries name based on native or partial name. Because the native name can be different. I add another filter to only include countries that have partial name keyword. This is to eliminate any return records that do not match the entered keyword. We then store the result into the variable named autoCompleteREsult and set the flag of autoCompleteProgress to true.

I have included a link to this free country API. To find more details about this free API, you can visit the link below.

https://restcountries.eu/#api-endpoints-name	

The final step is to add some style to our auto complete textbox component. Here is the full css code.

<style>
/*********** AUTO COMPLETE ************/
.loading-circle {
    background-color: #ffffff;
    background-image: url("loading.gif");
    background-size: 16px 16px;
    background-position: right center;
    background-repeat: no-repeat;
}

.hide-loading-circle {
    background: none;
}

.form-textinput{
	padding:8px 10px;
	border-radius:5px;
	border:solid 1px #ccc;
}

.autocomplete {
    position: relative;
}

.autocomplete-results {
    padding: 0;
    margin: 0;
    border: 1px solid #eeeeee;
    height: 120px;
    overflow: auto;
	background-color:#fdf8f3;
	border-radius:5px;
}

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

    .autocomplete-result:hover {
        background-color: #4AAE9B;
        color: white;
    }
/*********** END AUTO COMPLETE ************/
</style>
Please make sure the path of the loading.gif exists if you decide to copy the whole css code above.

Demo of Vue.js autocomplete textbox component

You can see the demo of Vue.js component below. If you have any question, feel free to post your message below.

Download Vue.js autocomplete textbox component File

You can download the Vue.js autocomplete file on the following link.

Download

If you need help with the code, feel free to post your message below.

Comments

Emidio Nhacudima
18 Sep, 2019
please add ++ toString() before toLowerCase() if (item.id.toString().toLowerCase().indexOf(keywordEntered.toLowerCase()) >= 0) { newData.push(item); }
Write Comment
0 characters entered. Maximum characters allowed are 1000 characters.

Related Articles

Data binding in Vue.js

Understanding the basic concept of data binding in Vue.js. In this tutorial, you will learn your first v-model in Vue.js and how the data binding works.