Autocomplete Web Component

Building on my previous article about testing web components I ran into a problem with a current development project that I felt a lightweight web component would be a good solution for. So I built one, documented it, and put it up on github for you all to use if you identify a similar need.

So the issue I had was to do with my current project, which is an online fitness studio for a startup enterprise called Home-Fit. The system requires that I can stream content from the instructor’s webcam into the homes of the delegates. For this to happen I need to be able to define a session, which of course is a period of time, scheduled to take place at a given time, with an instructor, and delegates.

So I need to be able to search for delegates, and add multiple delegates to a session. A dropdown list just seems clunky to me, and would need a separate box to store the items selected from the list. In a system of x 1000 delegates some sort of autosearch box is a far better bet. Something that searches as you type and gives you a list of suggestions as you type.

So thinking about this, I wanted to deliver something that can handle single selections, multiple selections, and gives the developer control over the way the suggestions are displayed, in the form of an html template.

I also wanted something that can plug into any REST api, and any shape of JSON data. So even if your api is returning data that is 5 levels deep, and the field names differ from the defaults of ‘ID’ and ‘Name’, no problem, just configure the control accordingly and off you go.

So the first example is a single select, that searches for a list of countries from the endpoint

This will return you some JSON that looks like this, if your search term was ‘afgh’ :

[{"name":"Afghanistan","topLevelDomain":[".af"],"alpha2Code":"AF","alpha3Code":"AFG","callingCodes":["93"],"capital":"Kabul","altSpellings":["AF","Afġānistān"],"region":"Asia","subregion":"Southern Asia","population":27657145,"latlng":[33.0,65.0],"demonym":"Afghan","area":652230.0,"gini":27.8,"timezones":["UTC+04:30"],"borders":["IRN","PAK","TKM","UZB","TJK","CHN"],"nativeName":"افغانستان","numericCode":"004","currencies":[{"code":"AFN","name":"Afghan afghani","symbol":"؋"}],"languages":[{"iso639_1":"ps","iso639_2":"pus","name":"Pashto","nativeName":"پښتو"},{"iso639_1":"uz","iso639_2":"uzb","name":"Uzbek","nativeName":"Oʻzbek"},{"iso639_1":"tk","iso639_2":"tuk","name":"Turkmen","nativeName":"Türkmen"}],"translations":{"de":"Afghanistan","es":"Afganistán","fr":"Afghanistan","ja":"アフガニスタン","it":"Afghanistan","br":"Afeganistão","pt":"Afeganistão","nl":"Afghanistan","hr":"Afganistan","fa":"افغانستان"},"flag":"","regionalBlocs":[{"acronym":"SAARC","name":"South Asian Association for Regional Cooperation","otherAcronyms":[],"otherNames":[]}],"cioc":"AFG"}]

And this is the implementation of our web component. This is only a handful of the attributes that have been implemented in this version. This says where to get the JSON from (url), the width of course, which is any valid width value, including em or percentages, nokeyword means there is no querystring required so the search term is just appended to the url, the placeholder is the same as any other HTML input field placeholder.

<ac-input url='' width='250px' nokeyword=true placeholder='Select country' ></ac-input> 
A single selection

Now you play…

This is nice enough, but doesn’t address my initial problem, but I wanted to address several different use cases with the one control as I felt this would be useful for future projects. By simply adding the attribute multiselect it drives a little differently. Take a look below.

Multiselect Example

Try it out yourself …

And that HTML template stuff, and destructuring attribute gives you full control over how to display your autocomplete suggestions and where to get the data from in the JSON format returned. The URL returns something that looks like this

{"page":1,"per_page":6,"total":12,"total_pages":2,"data":[{"id":1,"email":"[email protected]","first_name":"George","last_name":"Bluth","avatar":""},{"id":2,"email":"[email protected]","first_name":"Janet","last_name":"Weaver","avatar":""},{"id":3,"email":"[email protected]","first_name":"Emma","last_name":"Wong","avatar":""},{"id":4,"email":"[email protected]","first_name":"Eve","last_name":"Holt","avatar":""},{"id":5,"email":"[email protected]","first_name":"Charles","last_name":"Morris","avatar":""},{"id":6,"email":"[email protected]","first_name":"Tracey","last_name":"Ramos","avatar":""}]}

So we have to dig into the subitem data, and our fields of interest are the email field and the avatar field looks useful to us.

<div id='multipletemplate' class="section">
                <ac-input url='' width='250px' nokeyword=true subitem=data placeholder='Select user' multiselect itemtemplate="<div class='resultItem' id='${id}'><img src='${avatar}' style='border-radius:50%; width:50px; height:50px;'/>${email}</div>"></ac-input>

Note the use of a single mustache in the string interpolation. This is deliberate to keep it below the radar of any other string interpolation libraries you may be using, like mustache.js, which uses {{}}.

So there you have it. A versatile web component that addresses a number of different use cases and provides enough flexibility to the developer to use in many different scenarios. You could use it in an email app to build a TO list of email addresses, or use it to select multiple invoices for processing with a grid preview of the invoice information.

I would love to hear your feedback, either here or on github where you can find the project.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.