logo

Autocmplete example

Hero autocomplete

Type name or alter-ego of your favourite DC superhero. Type * to see all heroes.

HTML

To display autocomplete you will need two major elements, input and list.

  <p>
    <input id="filter-box" type="text" placeholder="Hero name">
  </p>
  <ul id="heroes-container" data-t5="heroes" class="ac off">
    <li repeat="hero in heroes | flat" data-idx="{{ hero.name }}">
      <span class="name">{{ hero.name }}</span> <span class="alt">{{ hero.alt }}</span>
    </li>
  </ul>

JavaScript

JS code is very simple in this example. Most of it is just setting up a data model, getting references to DOM elements and handling events. Full code can be downloaded from here. Here I'd like to point out three things.

Data Structure

Heroes data structure is quite simple, but nothing stands in our way to make it more complex if you'd need that kind of structure. See advanced data example.

  const heroes = [
    { name: 'Batman', alt: 'Bruce Wayne', all: "*" },
    { name: 'Flash', alt: ' Barry Allen', all: "*" },
    { name: 'Cyborg', alt: 'Victor Stone', all: "*"},
    { name: 'Wonder Woman', alt: 'Diana', all: "*" },
    { name: 'Superman', alt: 'Clark Kent', all: "*" },
    { name: 'Green Lantern', alt: 'Hal Jordan', all: "*" }
  ];

Template setup

In orde to render autocomplete template you need to do there things.

  t5.template()
    .filter('flat', (hero) => ~stringifyKeys(hero).indexOf(model.toLocaleLowerCase()) && model.length > 0)
    .render('heroes', {heroes});

Updating the model

On each input field update you need to re-render the template. Code below shows the most straightforward way of doing that. This could be optimised for example by adding a debouncing function, to make render more efficient.

  filterBox.addEventListener('keyup', (event) => {
    model = event.target.value;
    t5.render('heroes', {heroes});
    container.children.length > 0 ? container.classList.remove('off') : container.classList.add('off');
  });