Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(instantsearch): keep autocomplete in sync with query during navigation #1036

Merged
merged 8 commits into from
Nov 3, 2022
4 changes: 0 additions & 4 deletions examples/instantsearch/env.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import * as preact from 'preact';

// Parcel picks the `source` field of the monorepo packages and thus doesn't
// apply the Babel config. We therefore need to manually override the constants
// in the app, as well as the React pragmas.
// See https://twitter.com/devongovett/status/1134231234605830144
(global as any).__DEV__ = process.env.NODE_ENV !== 'production';
(global as any).__TEST__ = false;
(global as any).h = preact.h;
(global as any).React = preact;
7 changes: 3 additions & 4 deletions examples/instantsearch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@
"@algolia/autocomplete-plugin-query-suggestions": "1.7.3",
"@algolia/autocomplete-plugin-recent-searches": "1.7.3",
"@algolia/autocomplete-theme-classic": "1.7.3",
"@algolia/client-search": "4.9.1",
"algoliasearch": "4.9.1",
"instantsearch.js": "4.22.0",
"preact": "10.5.13"
"@algolia/client-search": "4.14.2",
"algoliasearch": "4.14.2",
"instantsearch.js": "4.49.0"
},
"devDependencies": {
"parcel": "2.7.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/instantsearch/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import { startAutocomplete } from './autocomplete';
import { search } from './instantsearch';

search.start();
startAutocomplete();
startAutocomplete(search);
120 changes: 62 additions & 58 deletions examples/instantsearch/src/autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { autocomplete } from '@algolia/autocomplete-js';
import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
import { h, Fragment } from 'preact';
import { InstantSearch } from 'instantsearch.js';

import {
debouncedSetInstantSearchUiState,
Expand Down Expand Up @@ -42,29 +42,27 @@ function getItemUrl({ query, category }) {
});
}

function ItemWrapper({ children, query, category }) {
function getItemWrapper({ html, children, query, category }) {
const uiState = {
query,
hierarchicalMenu: {
[INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE]: [category],
},
};

return (
<a
className="aa-ItemLink"
href={getInstantSearchUrl(uiState)}
onClick={(event) => {
if (!isModifierEvent(event)) {
// Bypass the original link behavior if there's no event modifier
// to set the InstantSearch UI state without reloading the page.
event.preventDefault();
}
}}
>
{children}
</a>
);
return html`<a
class="aa-ItemLink"
href=${getInstantSearchUrl(uiState)}
onClick=${(event) => {
if (!isModifierEvent(event)) {
// Bypass the original link behavior if there's no event modifier
// to set the InstantSearch UI state without reloading the page.
event.preventDefault();
}
}}
>
${children}
</a>`;
}

const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
Expand Down Expand Up @@ -94,15 +92,14 @@ const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({
// and plug it to the InstantSearch router.
item(params) {
const { children } = (source.templates.item(params) as any).props;
const { item, html } = params;

return (
<ItemWrapper
query={params.item.label}
category={params.item.category}
>
{children}
</ItemWrapper>
);
return getItemWrapper({
query: item.label,
category: item.category,
html,
children,
});
},
},
};
Expand All @@ -115,7 +112,7 @@ const querySuggestionsPluginInCategory = createQuerySuggestionsPlugin({
getSearchParams() {
const currentCategory = getInstantSearchCurrentCategory();

return recentSearchesPlugin.data.getAlgoliaSearchParams({
return recentSearchesPlugin.data!.getAlgoliaSearchParams({
hitsPerPage: 3,
facetFilters: [
`${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:${currentCategory}`,
Expand Down Expand Up @@ -152,22 +149,22 @@ const querySuggestionsPluginInCategory = createQuerySuggestionsPlugin({
},
templates: {
...source.templates,
header() {
return (
<Fragment>
<span className="aa-SourceHeaderTitle">In {currentCategory}</span>
<div className="aa-SourceHeaderLine" />
</Fragment>
);
header({ html }) {
return html`
<span class="aa-SourceHeaderTitle">In ${currentCategory}</span>
<div class="aa-SourceHeaderLine" />
`;
},
item(params) {
const { children } = (source.templates.item(params) as any).props;
const { item, html } = params;

return (
<ItemWrapper query={params.item.query} category={currentCategory}>
{children}
</ItemWrapper>
);
return getItemWrapper({
query: item.query,
category: currentCategory,
html,
children,
});
},
},
};
Expand All @@ -181,12 +178,12 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({
const currentCategory = getInstantSearchCurrentCategory();

if (!currentCategory) {
return recentSearchesPlugin.data.getAlgoliaSearchParams({
return recentSearchesPlugin.data!.getAlgoliaSearchParams({
hitsPerPage: 6,
});
}

return recentSearchesPlugin.data.getAlgoliaSearchParams({
return recentSearchesPlugin.data!.getAlgoliaSearchParams({
hitsPerPage: 3,
facetFilters: [
`${INSTANT_SEARCH_INDEX_NAME}.facets.exact_matches.${INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE}.value:-${currentCategory}`,
Expand Down Expand Up @@ -229,29 +226,26 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({
},
templates: {
...source.templates,
header() {
header({ html }) {
if (!currentCategory) {
return null;
}

return (
<Fragment>
<span className="aa-SourceHeaderTitle">In other categories</span>
<div className="aa-SourceHeaderLine" />
</Fragment>
);
return html`
<span class="aa-SourceHeaderTitle">In other categories</span>
<div class="aa-SourceHeaderLine" />
`;
},
item(params) {
const { children } = (source.templates.item(params) as any).props;
const { item, html } = params;

return (
<ItemWrapper
query={params.item.query}
category={params.item.__autocomplete_qsCategory}
>
{children}
</ItemWrapper>
);
return getItemWrapper({
query: item.query,
category: item.__autocomplete_qsCategory,
html,
children,
});
},
},
};
Expand All @@ -260,8 +254,10 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({

const searchPageState = getInstantSearchUiState();

export function startAutocomplete() {
autocomplete({
export function startAutocomplete(searchInstance: InstantSearch) {
let skipInstantSearchStateUpdate = false;

const { setQuery } = autocomplete({
container: '#autocomplete',
placeholder: 'Search for products',
openOnFocus: true,
Expand Down Expand Up @@ -292,9 +288,17 @@ export function startAutocomplete() {
});
},
onStateChange({ prevState, state }) {
if (prevState.query !== state.query) {
if (!skipInstantSearchStateUpdate && prevState.query !== state.query) {
debouncedSetInstantSearchUiState({ query: state.query });
}
skipInstantSearchStateUpdate = false;
},
});

window.addEventListener('popstate', () => {
skipInstantSearchStateUpdate = true;
setQuery(
(searchInstance.helper && searchInstance.helper.state.query) || ''
);
});
}
28 changes: 16 additions & 12 deletions examples/instantsearch/src/instantsearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,16 @@ search.addWidgets([
}));
},
templates: {
item: `
item: (hit, { html, components }) => html`
<article class="hit">
<div class="hit-image">
<img src="{{image}}" alt="{{name}}">
<img src="${hit.image}" alt="${hit.name}" />
</div>
<div>
<h1>
{{#helpers.snippet}}{ "attribute": "name" }{{/helpers.snippet}}
</h1>
<h1>${components.Snippet({ hit, attribute: 'name' })}</h1>
<div>
By <strong>{{brand}}</strong> in <strong>{{category}}</strong>
By <strong>${hit.brand}</strong> in
<strong>${hit.category}</strong>
</div>
</div>

Expand All @@ -81,7 +80,8 @@ search.addWidgets([
gap: 8px;
"
>
{{#rating}}
${hit.rating > 0 &&
html`
<div
style="
display: grid;
Expand All @@ -101,11 +101,13 @@ search.addWidgets([
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"
/>
</svg>
{{rating}}
${hit.rating}
</div>
{{/rating}}
`}

<div
style="
Expand All @@ -130,9 +132,11 @@ search.addWidgets([
top: 1px;
"
>
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
></path>
</svg>
<span>{{comments}}</span>
<span>${hit.comments}</span>
</div>
</div>
</article>
Expand Down
Loading