Skip to content

Commit aa7caa9

Browse files
authored
docs(example): update vue-instantsearch example to reflect guide steps (#900)
1 parent 4430816 commit aa7caa9

File tree

3 files changed

+266
-260
lines changed

3 files changed

+266
-260
lines changed

examples/vue-instantsearch/src/App.vue

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
<template>
22
<div>
3-
<header class="header">
4-
<div class="header-wrapper wrapper">
5-
<nav class="header-nav">
6-
<a href="/">Home</a>
7-
</nav>
8-
<div id="autocomplete"></div>
9-
</div>
10-
</header>
11-
123
<ais-instant-search
134
:search-client="searchClient"
145
:index-name="indexName"
156
:routing="routing"
16-
:middlewares="middlewares"
177
>
8+
<header class="header">
9+
<div class="header-wrapper wrapper">
10+
<nav class="header-nav">
11+
<a href="/">Home</a>
12+
</nav>
13+
<Autocomplete />
14+
</div>
15+
</header>
16+
1817
<ais-configure
1918
:attributes-to-snippet.camel="['name:7', 'description:15']"
2019
:snippet-ellipsis-text.camel="'…'"
@@ -32,7 +31,6 @@
3231
</ais-panel>
3332
</div>
3433
<div>
35-
<ais-search-box><template></template></ais-search-box>
3634
<ais-hits>
3735
<template v-slot:item="{ item }">
3836
<article class="hit">
@@ -62,11 +60,12 @@
6260
import { history as historyRouter } from 'instantsearch.js/es/lib/routers';
6361
import { singleIndex as singleIndexMapping } from 'instantsearch.js/es/lib/stateMappings';
6462
65-
import { autocompleteMiddleware } from './autocompleteMiddleware';
63+
import Autocomplete from './Autocomplete.vue';
6664
import { INSTANT_SEARCH_INDEX_NAME } from './constants';
6765
import { searchClient } from './searchClient';
6866
6967
export default {
68+
components: { Autocomplete },
7069
data() {
7170
return {
7271
searchClient,
@@ -75,7 +74,6 @@ export default {
7574
router: historyRouter(),
7675
stateMapping: singleIndexMapping(INSTANT_SEARCH_INDEX_NAME),
7776
},
78-
middlewares: [autocompleteMiddleware],
7977
};
8078
},
8179
};
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
<template>
2+
<div ref="autocompleteContainer"></div>
3+
</template>
4+
5+
<script lang="jsx">
6+
import { Fragment, render } from 'vue';
7+
8+
import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
9+
import { connectSearchBox } from 'instantsearch.js/es/connectors';
10+
import { autocomplete } from '@algolia/autocomplete-js';
11+
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
12+
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
13+
14+
import '@algolia/autocomplete-theme-classic';
15+
16+
import { createElement } from './utils/createElement';
17+
import {
18+
INSTANT_SEARCH_INDEX_NAME,
19+
INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE,
20+
} from './constants';
21+
import { searchClient } from './searchClient';
22+
23+
function debounce(fn, time) {
24+
let timerId;
25+
26+
return function (...args) {
27+
if (timerId) {
28+
clearTimeout(timerId);
29+
}
30+
31+
timerId = setTimeout(() => fn(...args), time);
32+
};
33+
}
34+
35+
export default {
36+
mixins: [createWidgetMixin({ connector: connectSearchBox })],
37+
mounted() {
38+
const { instantSearchInstance } = this;
39+
function getInstantSearchCurrentCategory() {
40+
const indexRenderState =
41+
instantSearchInstance.renderState[INSTANT_SEARCH_INDEX_NAME];
42+
43+
const refinedCategory = indexRenderState?.hierarchicalMenu?.[
44+
INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE
45+
]?.items?.find(({ isRefined }) => isRefined);
46+
47+
return refinedCategory?.value;
48+
}
49+
50+
function setInstantSearchUiState({
51+
query,
52+
category,
53+
resetCategory = false,
54+
}) {
55+
let hierarchicalMenu;
56+
if (resetCategory) {
57+
hierarchicalMenu = {
58+
hierarchicalMenu: { [INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [] },
59+
};
60+
} else if (!category) {
61+
hierarchicalMenu = {};
62+
} else {
63+
hierarchicalMenu = {
64+
hierarchicalMenu: {
65+
[INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
66+
},
67+
};
68+
}
69+
70+
instantSearchInstance.setUiState((uiState) => ({
71+
...uiState,
72+
[INSTANT_SEARCH_INDEX_NAME]: {
73+
...uiState[INSTANT_SEARCH_INDEX_NAME],
74+
page: 1,
75+
query,
76+
...hierarchicalMenu,
77+
},
78+
}));
79+
}
80+
81+
const debouncedSetInstantSearchUiState = debounce(
82+
setInstantSearchUiState,
83+
500
84+
);
85+
86+
const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
87+
key: 'instantsearch',
88+
limit: 3,
89+
transformSource({ source }) {
90+
return {
91+
...source,
92+
onSelect({ item }) {
93+
setInstantSearchUiState({
94+
query: item.label,
95+
category: item.category,
96+
});
97+
},
98+
};
99+
},
100+
});
101+
102+
const querySuggestionPluginInCategory = createQuerySuggestionsPlugin({
103+
searchClient,
104+
indexName: 'instant_search_demo_query_suggestions',
105+
getSearchParams() {
106+
const currentCategory = getInstantSearchCurrentCategory();
107+
return recentSearchesPlugin.data.getAlgoliaSearchParams({
108+
hitsPerPage: 3,
109+
facetFilters: [
110+
`${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.categories.value:${currentCategory}`,
111+
],
112+
});
113+
},
114+
transformSource({ source }) {
115+
const currentCategory = getInstantSearchCurrentCategory();
116+
117+
return {
118+
...source,
119+
sourceId: 'querySuggestionsPluginInCategory',
120+
onSelect({ item }) {
121+
setInstantSearchUiState({
122+
query: item.query,
123+
category: currentCategory,
124+
});
125+
},
126+
getItems(params) {
127+
if (!currentCategory) {
128+
return [];
129+
}
130+
131+
return source.getItems(params);
132+
},
133+
templates: {
134+
...source.templates,
135+
header({ items }) {
136+
if (items.length === 0) {
137+
return null;
138+
}
139+
140+
return (
141+
<Fragment>
142+
<span className="aa-SourceHeaderTitle">
143+
In {currentCategory}
144+
</span>
145+
<span className="aa-SourceHeaderLine"></span>
146+
</Fragment>
147+
);
148+
},
149+
},
150+
};
151+
},
152+
});
153+
154+
const querySuggestionsPlugin = createQuerySuggestionsPlugin({
155+
searchClient,
156+
indexName: 'instant_search_demo_query_suggestions',
157+
getSearchParams() {
158+
const currentCategory = getInstantSearchCurrentCategory();
159+
160+
if (!currentCategory) {
161+
return recentSearchesPlugin.data.getAlgoliaSearchParams({
162+
hitsPerPage: 6,
163+
});
164+
}
165+
166+
return recentSearchesPlugin.data.getAlgoliaSearchParams({
167+
hitsPerPage: 3,
168+
facetFilters: [
169+
`${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.categories.value:-${currentCategory}`,
170+
],
171+
});
172+
},
173+
categoryAttribute: [
174+
'instant_search',
175+
'facets',
176+
'exact_matches',
177+
INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE,
178+
],
179+
transformSource({ source }) {
180+
const currentCategory = getInstantSearchCurrentCategory();
181+
182+
return {
183+
...source,
184+
sourceId: 'querySuggestionsPlugin',
185+
onSelect({ item }) {
186+
setInstantSearchUiState({
187+
query: item.query,
188+
category: item.__autocomplete_qsCategory,
189+
});
190+
},
191+
getItems(params) {
192+
if (!params.state.query) {
193+
return [];
194+
}
195+
196+
return source.getItems(params);
197+
},
198+
templates: {
199+
...source.templates,
200+
header({ items }) {
201+
if (!currentCategory || items.length === 0) {
202+
return null;
203+
}
204+
205+
return (
206+
<Fragment>
207+
<span className="aa-SourceHeaderTitle">
208+
In other categories
209+
</span>
210+
<span className="aa-SourceHeaderLine" />
211+
</Fragment>
212+
);
213+
},
214+
},
215+
};
216+
},
217+
});
218+
219+
const initialState =
220+
instantSearchInstance.mainIndex.getHelper()?.state || {};
221+
222+
this.autocompleteInstance = autocomplete({
223+
container: this.$refs.autocompleteContainer,
224+
placeholder: 'Search for products',
225+
detachedMediaQuery: 'none',
226+
openOnFocus: true,
227+
plugins: [
228+
recentSearchesPlugin,
229+
querySuggestionPluginInCategory,
230+
querySuggestionsPlugin,
231+
],
232+
initialState: { query: initialState.query || '' },
233+
onSubmit({ state }) {
234+
setInstantSearchUiState({ query: state.query });
235+
},
236+
onReset() {
237+
setInstantSearchUiState({ query: '', resetCategory: true });
238+
},
239+
onStateChange({ prevState, state }) {
240+
if (prevState.query !== state.query) {
241+
debouncedSetInstantSearchUiState({ query: state.query });
242+
}
243+
},
244+
renderer: {
245+
createElement,
246+
Fragment,
247+
},
248+
render({ children }, root) {
249+
render(children, root);
250+
},
251+
});
252+
},
253+
beforeUnmount() {},
254+
};
255+
</script>

0 commit comments

Comments
 (0)