Icon search ui white

How do I display results from multiple indices with autocomplete.js?

Last updated 01 August 2017

Before starting

Make sure you understand the following Algolia concepts before starting this tutorial:

Introduction

Autocomplete menus offer many possibilities for engaging users. You can find an example of a complex multi-category dropdown menu live on birchbox.fr.

Dataset

We are going to display the results from 2 datasets: player but also team information.

Different types of data should be created as different indices. This allows you to create separate ranking strategies more tailored to each type of data.

Players

[
  {
    "name": "Sam Young",
    "team": "Grizzlies",
    "points": 595
  },
  {
    "name": "Thaddeus Young",
    "team": "76ers",
    "points": 926
  }
  [...]
]

You can download the dataset here. Have look at how to import it with Algolia here

Teams

[
  {
    "name": "Hawks",
    "location": "Atlanta",
    "logoUrl": "Hawks_Atlanta.gif",
    "score": 595.5714285714286
  },
  {
    "name": "Celtics",
    "location": "Boston",
    "logoUrl": "Celtics_Boston.gif",
    "score": 428.2105263157895
  }
  // [...]
]

You can download the dataset here. Have look at how to import it with Algolia here

Configuring the indices

For both indices we specify both searchable attributes and custom ranking criterion.

Players

<?php
$client->initIndex("YourIndexName")->setSettings(array(
  "searchableAttributes" => array(
    "name",
    "team"
  ),
   "customRanking" => array(
      "desc(points)"
  )
));

For players, it makes sense to allow users to search by player name or team name, as both of these attributes will be displayed. To rank the players, we have added a “points” attribute that reflects the amount of points each player has scored (the higher the scores, the better).

Teams

<?php
$client->initIndex("YourIndexName")->setSettings(array(
  "searchableAttributes" => array(
    "name",
    "location"
  ),
  "customRanking" => array(
    "asc(name)"
  )
));

For teams, it makes sense to allow users to search by team name or location, as both of these attributes will be displayed. To rank the teams, we have added a “score” attribute that reflects the average of the points of a team’s respective players.

HTML

<!-- Include stylesheet -->
<link href="app.css" rel=stylesheet />

<!-- HTML Markup -->
<div class="aa-input-container" id="aa-input-container">
    <input type="search" id="aa-search-input" class="aa-input-search" placeholder="Search for players or teams..." name="search" autocomplete="off" />
    <svg class="aa-input-icon" viewBox="654 -372 1664 1664">
        <path d="M1806,332c0-123.3-43.8-228.8-131.5-316.5C1586.8-72.2,1481.3-116,1358-116s-228.8,43.8-316.5,131.5  C953.8,103.2,910,208.7,910,332s43.8,228.8,131.5,316.5C1129.2,736.2,1234.7,780,1358,780s228.8-43.8,316.5-131.5  C1762.2,560.8,1806,455.3,1806,332z M2318,1164c0,34.7-12.7,64.7-38,90s-55.3,38-90,38c-36,0-66-12.7-90-38l-343-342  c-119.3,82.7-252.3,124-399,124c-95.3,0-186.5-18.5-273.5-55.5s-162-87-225-150s-113-138-150-225S654,427.3,654,332  s18.5-186.5,55.5-273.5s87-162,150-225s138-113,225-150S1262.7-372,1358-372s186.5,18.5,273.5,55.5s162,87,225,150s113,138,150,225  S2062,236.7,2062,332c0,146.7-41.3,279.7-124,399l343,343C2305.7,1098.7,2318,1128.7,2318,1164z" />
    </svg>
</div>
<!-- Include AlgoliaSearch JS Client and autocomplete.js library -->
<script src="https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js"></script>
<script src="https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.min.js"></script>
<script src="app.js"></script>

JS (app.js)

var client = algoliasearch("4J2JTO3FLK", "2f4cff0198aca3ee49fffa6df138e260")
var players = client.initIndex('players');
var teams = client.initIndex('teams');

autocomplete('#aa-search-input', {}, [
    {
      source: autocomplete.sources.hits(players, { hitsPerPage: 3 }),
      displayKey: 'name',
      templates: {
        header: '<div class="aa-suggestions-category">Players</div>',
        suggestion: function(suggestion) {
          return '<span>' +
            suggestion._highlightResult.name.value + '</span><span>'
              + suggestion._highlightResult.team.value + '</span>';
        }
      }
    },
    {
      source: autocomplete.sources.hits(teams, { hitsPerPage: 3 }),
      displayKey: 'name',
      templates: {
        header: '<div class="aa-suggestions-category">Teams</div>',
        suggestion: function(suggestion) {
          return '<span>' +
            suggestion._highlightResult.name.value + '</span><span>'
              + suggestion._highlightResult.location.value + '</span>';
        }
      }
    }
]);

CSS Styles (app.css)

.aa-input-container {
  display: inline-block;
  position: relative;
}
.aa-input-search {
  width: 300px;
  padding: 12px 28px 12px 12px;
  border: 1px solid #e4e4e4;
  box-sizing: border-box;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
.aa-input-search::-webkit-search-decoration, .aa-input-search::-webkit-search-cancel-button,
.aa-input-search::-webkit-search-results-button, .aa-input-search::-webkit-search-results-decoration {
    display: none;
}
.aa-input-icon {
  height: 16px;
  width: 16px;
  position: absolute;
  top: 50%;
  right: 16px;
  -webkit-transform: translateY(-50%);
          transform: translateY(-50%);
  fill: #e4e4e4;
  pointer-events: none;
}
.aa-dropdown-menu {
  background-color: #fff;
  border: 1px solid rgba(228, 228, 228, 0.6);
  min-width: 300px;
  margin-top: 10px;
  box-sizing: border-box;
}
.aa-suggestion {
  padding: 6px 12px;
  cursor: pointer;
}
.aa-suggestions-category {
  border-bottom: 1px solid rgba(228, 228, 228, 0.6);
  border-top: 1px solid rgba(228, 228, 228, 0.6);
  padding: 6px 12px;
}
.aa-dropdown-menu {
  min-width: 600px;
}
.aa-dropdown-menu > div {
  display: inline-block;
  width: 50%;
  vertical-align: top;
}
.aa-empty {
  padding: 6px 12px;
}
@import 'https://fonts.googleapis.com/css?family=Montserrat:400,700';
.aa-input-container {
  display: inline-block;
  position: relative;
}
.aa-input-search {
  width: 300px;
  padding: 12px 28px 12px 12px;
  border: 2px solid #e4e4e4;
  border-radius: 4px;
  -webkit-transition: .2s;
  transition: .2s;
  font-family: "Montserrat", sans-serif;
  box-shadow: 4px 4px 0 rgba(241, 241, 241, 0.35);
  font-size: 11px;
  box-sizing: border-box;
  color: #333;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
.aa-input-search::-webkit-search-decoration, .aa-input-search::-webkit-search-cancel-button,
.aa-input-search::-webkit-search-results-button, .aa-input-search::-webkit-search-results-decoration {
  display: none;
}
.aa-input-search:focus {
  outline: 0;
  border-color: #3a96cf;
  box-shadow: 4px 4px 0 rgba(58, 150, 207, 0.1);
}
.aa-input-icon {
  height: 16px;
  width: 16px;
  position: absolute;
  top: 50%;
  right: 16px;
  -webkit-transform: translateY(-50%);
          transform: translateY(-50%);
  fill: #e4e4e4;
  pointer-events: none;
}
.aa-hint {
  color: #e4e4e4;
}
.aa-dropdown-menu {
  background-color: #fff;
  border: 2px solid rgba(228, 228, 228, 0.6);
  border-top-width: 0;
  font-family: "Montserrat", sans-serif;
  width: 300px;
  margin-top: 10px;
  box-shadow: 4px 4px 0 rgba(241, 241, 241, 0.35);
  font-size: 11px;
  border-radius: 4px;
  box-sizing: border-box;
}
.aa-suggestion {
  padding: 6px 12px;
  cursor: pointer;
  -webkit-transition: .2s;
  transition: .2s;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
}
.aa-suggestion:hover, .aa-suggestion.aa-cursor {
  background-color: rgba(241, 241, 241, 0.35);
}
.aa-suggestion > div {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
  width: 100%;
}
.aa-suggestion span:first-child {
  color: #333;
}
.aa-suggestion span:last-child {
  text-transform: uppercase;
  color: #a9a9a9;
}
.aa-suggestion img {
  max-width: 80px;
  margin-right: 10px;
}
.aa-suggestions-category {
  text-transform: uppercase;
  border-bottom: 2px solid rgba(228, 228, 228, 0.6);
  border-top: 2px solid rgba(228, 228, 228, 0.6);
  padding: 10px;
  color: #a9a9a9;
  padding: 6px 12px;
  text-align: left;
}
.aa-suggestion span:first-child em, .aa-suggestion span:last-child em {
  font-weight: 700;
  font-style: normal;
  background-color: rgba(58, 150, 207, 0.1);
  padding: 2px 0 2px 2px;
}
.aa-dropdown-menu {
  width: 600px;
}
.aa-dropdown-menu > div {
  display: inline-block;
  width: 50%;
  vertical-align: top;
}
.aa-empty {
  padding: 6px 12px;
}

The “CSS - Basic” tab contains out-of-the-box structural styles. For the fully-themed version (as shown in the live demo), copy the “CSS - Themed” tab.

See it in action

© Algolia - Privacy Policy