Tutorials / Building Search UI / How to display results from multiple indices with autocomplete.js
May. 10, 2019

How to Display Results from Multiple Indices with Autocomplete.js

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

1
2
3
4
5
6
7
8
9
10
11
12
13
[
  {
    "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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[
  {
    "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

1
2
3
4
5
6
7
8
9
$client->initIndex("players")->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

1
2
3
4
5
6
7
8
9
$client->initIndex("teams")->setSettings(array(
  "searchableAttributes" => array(
    "name",
    "location"
  ),
  "customRanking" => array(
    "asc(score)"
  )
));

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 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>

jsDelivr is a third-party CDN. We are not able to provide support regarding third party services.

JS (app.js)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const client = algoliasearch("4J2JTO3FLK", "2f4cff0198aca3ee49fffa6df138e260");
const players = client.initIndex('players');
const 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({_highlightResult}) {
          return `<span>${_highlightResult.name.value}</span><span>${_highlightResult.team.value}</span>`;
        }
      }
    },
    {
      source: autocomplete.sources.hits(teams, { hitsPerPage: 3 }),
      displayKey: 'name',
      templates: {
        header: '<div class="aa-suggestions-category">Teams</div>',
        suggestion({_highlightResult}) {
          return `<span>${_highlightResult.name.value}</span><span>${_highlightResult.location.value}</span>`;
        }
      }
    }
]);

CSS Styles (app.css)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.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);
  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 > div {
  display: inline-block; 
  width: 100%; 
  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

Did you find this page helpful?