Build a Query Suggestions UI with Vue InstantSearch
On this page
To help users with their search, Algolia provides Query Suggestions. This feature creates an index of your user’s best queries. You can then use this index to propose suggestions to your users as they’re typing into the ais-search-box
. Once you’ve configured the generation of the Query Suggestions index, you need to query this index as well. Use multi-index search to do that.
This guide shows how to use a search box to display a list of suggestions and their associated categories. Once users select a suggestion, Algolia will apply the query and the category.
If you’re building an autocomplete with Query Suggestions, you should use the Autocomplete library which lets you build a full-featured, accessible autocomplete experience. This is the recommended way of building an autocomplete search with Algolia.
Working example
This code has been specifically created for Vue 2. Some modifications may be required for it to work correctly in Vue 3.
Refine your results with the suggestions
The first step is to set up a custom autocomplete component with the
Vue Autosuggest library.
You must then wrap the component with the ais-autocomplete
connector. You can find more information in the guide on autocomplete.
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
<template>
<ais-instant-search
:search-client="searchClient"
index-name="instant_search_demo_query_suggestions"
>
<ais-configure :hitsPerPage="5" />
<ais-autocomplete>
<template v-slot="{ currentRefinement, indices, refine }">
<vue-autosuggest
:suggestions="indicesToSuggestions(indices)"
@selected="onSelect"
:input-props="{
style: 'width: 100%',
onInputChange: refine,
placeholder: 'Search here…',
}"
>
<template v-slot="{ suggestion }">
<ais-highlight attribute="query" :hit="suggestion.item" />
</template>
</vue-autosuggest>
</template>
</ais-autocomplete>
</ais-instant-search>
</template>
<script>
import { VueAutosuggest } from 'vue-autosuggest';
export default {
components: { VueAutosuggest },
methods: {
onSelect(selected) {
if (selected) {
console.log('selected');
}
},
indicesToSuggestions(indices) {
return indices.map(({ hits }) => ({
data: hits.map(hit => {
return {
...hit,
// this is for Vue AutoSuggest
name: hit.query,
};
}),
}));
},
},
};
</script>
Now that you have your autocomplete component, you can create the multi-index search experience. The ais-autocomplete
widget reads from two indices: instant_search_demo_query_suggestions
and instant_search
. The first index widget is implied by the creation of the ais-instant-search
widget. You can find more information in the autocomplete guide.
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<template>
<div>
<ais-instant-search
:search-client="searchClient"
index-name="instant_search_demo_query_suggestions"
>
<ais-configure :hitsPerPage="5" />
<ais-index index-name="instant_search" />
<ais-autocomplete>
<template v-slot="{ currentRefinement, indices, refine }">
<vue-autosuggest
:suggestions="indicesToSuggestions(indices)"
@selected="onSelect"
:input-props="{
style: 'width: 100%',
onInputChange: refine,
placeholder: 'Search here…',
}"
>
<template v-slot="{ suggestion }">
<ais-highlight
:hit="suggestion.item"
attribute="query"
v-if="suggestion.item.query"
/>
<ais-highlight
:hit="suggestion.item"
attribute="name"
v-else
/>
<strong v-if="suggestion.item.price">
$ {{ suggestion.item.price }}
</strong>
<img
:src="suggestion.item.image"
style="height: 50px;"
v-if="suggestion.item.image"
/>
</template>
</vue-autosuggest>
</template>
</ais-autocomplete>
</ais-instant-search>
</div>
</template>
<script>
import { VueAutosuggest } from 'vue-autosuggest';
export default {
components: { VueAutosuggest },
methods: {
onSelect(selected) {
if (selected) {
const { query } = selected.item;
this.query = query;
}
},
indicesToSuggestions(indices) {
return indices.map(({ hits }) => ({
data: hits.map(hit => {
return {
...hit,
// this is for Vue Autosuggest
name: hit.query,
};
}),
}));
},
},
};
</script>
That’s it. You have set up your autocomplete multi-index search experience, and users can now select a suggestion and use it to search the main index.
Use the related categories in the autocomplete
A typical use of autocomplete is to display both relevant categories and suggestions. Then when a user selects a suggestion, both the suggestion and the associated category are used to refine the search. For this example, the relevant categories are stored on the suggestions records. You must update your render function to display the categories with the suggestions. For simplicity and brevity of the code, assume that all suggestions have categories, but this isn’t the case in the actual dataset. Take a look at the complete example to see the actual implementation.
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
<template>
<!-- ... -->
<template v-slot="{ suggestion }">
<span>
<ais-highlight attribute="query" :hit="suggestion.item" />
<span>
<em>
in
<span v-if="suggestion.item.category">
{{ suggestion.item.category.value }}
</span>
<span v-else> All categories </span>
</em>
</span>
</span>
</template>
<!-- ... -->
</template>
<script>
export default {
methods:
indicesToSuggestions(indices) {
return indices.map(({ hits }) => ({
data: hits.map(hit => {
// categories is an array, but you only want the first element
// hit.instant_search is undefined if there are no matched categories
const [category] =
(hit.instant_search &&
hit.instant_search.facets.exact_matches.categories) ||
[];
return {
...hit,
category,
name: hit.query,
};
}),
}));
},
},
};
</script>
Now that you can display categories, you can use them to refine the main search. Use the ais-configure
widget with disjunctiveFacets
and disjunctiveFacetsRefinement
. These two parameters are the same as internally used in a refinement list.
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
<template>
<!-- ... -->
<ais-instant-search
:search-client="searchClient"
index-name="instant_search"
>
<!-- optionally to display the selected category -->
<ais-current-refinements />
<ais-configure
:query="query"
:disjunctiveFacets="['categories']"
:disjunctiveFacetsRefinements="disjunctiveFacetsRefinements"
/>
<!-- ... -->
</ais-instant-search>
</template>
<script>
export default {
data() {
return {
query: '',
disjunctiveFacetsRefinements: undefined,
};
},
methods: {
onSelect(selected) {
if (selected) {
const { query, category } = selected.item;
this.query = query;
this.disjunctiveFacetsRefinements = category && {
categories: [category.value],
};
}
},
},
};
</script>
That’s it. When a suggestion is selected, both the query and the category are applied to the main search.