Why is Algolia removing my url query parameters? (Vue Instant Search + no-ssr Nuxt)

Viewed 262

TL;DR for future visitors with the same problem, see my answer below

I am using algolia for search within my Nuxt app. As I would like users to enter a search term on the dashboard and be redirected to the "full" search page including results after initiating the search, I need to use algolia routing.

What should happen

  1. User enters search term in dashboard and presses the "search"-button.
  2. The app directs the user to https://example.com/search?term=THE_SEARCH_TERM.
  3. The page loads showing the results for the entered search term.

What's happening

The app directs the user to https://example.com/search?term=THE_SEARCH_TERM and immediately redirects to https://example.com/search, removing the search parameter and therefore not displaying the results for the query.


As mentioned I am using Nuxt, but the component is not rendered on the server side. The template simplified template would be:

<client-only>
<ais-instant-search
  index-name="my_index"
  :search-client="algoliaSearchClient"
  :routing="algoliaRouting"
>
  <ais-index />
  <ais-configure v-bind="searchParameters" />
  <ais-autocomplete>
    <ais-search-box />
  </ais-autocomplete>
</ais-instant-search>
</client-only>

I am initialising the search client as well as the routing in a global mixin like so:

    data() {
        return {
            algoliaSearchClient: algoliasearch(
                "xxx",
                "xxxxx"
            ),
            algoliaRouting: {
                router: historyRouter({
                    parseURL(data: any) {
                        const { query = "" } = data.qsModule.parse(
                            data.location.search.slice(1)
                        )

                        return {
                            query,
                        }
                    },
                }),
                stateMapping: {
                    stateToRoute(uiState: any) {
                        const indexUiState = uiState[indexName]
                        return {
                            term: indexUiState.query,
                            categories:
                                indexUiState.menu &&
                                indexUiState.menu.categories,
                            brand:
                                indexUiState.refinementList &&
                                indexUiState.refinementList.brand,
                            page: indexUiState.page,
                        }
                    },
                    routeToState(routeState: any) {
                        const term = routeState?.term
                        return {
                            [indexName]: {
                                query: term,
                            },
                        }
                    },
                },
            },
        }
    }

Using the provided stateMapping and router constructors resulted in the same behaviour.


Remarks The behaviour is only observed when using the router to push to the url. If the url containing a search term is copied and entered manually, the query parameters are not removed.


1 Answers

Possible workaround for future visitors, this solution is not using algolia routing!

A workaround that works pretty well is not using algolia routing at all.

It is actually quite easy to implement this functionality on your own.

  1. Add the (for some reason undocumented) value prop to <ais-search-box /> and set its value to the query parameter.
<ais-search-box :value="$route.query.term" />

This already takes care of everything needed to fetch the query parameter from the url and initiate the search. Now we need to add the logic to update the query term as the user types.

  1. Update the URL query on input
<ais-search-box :value="$route.query.term">
  <template #default>
    <input
      @input="
        (e) => 
          handleSearchBoxInput(e.currentTarget.value, refine)
        "
    />
  </template>
</ais-search-box>

We don't have to instantly update the url query on every keystroke, so I'm using a simple debounce function (imported from lodash) to improve performance.

const debounceMethod = debounce((fn: Function, ...args) => {
  fn(...args)
}, 300)


const handleSearchBoxInput = (value: string, refine: (query: string) => void) => {
            this.debounceMethod(() => {
            const searchParams = new URLSearchParams(window.location.search)
            searchParams.set("term", value)
            const newRelativePathQuery =
                window.location.pathname + "?" + searchParams.toString()
            history.pushState(null, "", newRelativePathQuery)
        })
        refine(value)

}

This works pretty much identically to how algolia routing would work for a simple use-case such as only passing a query. It will most likely become a lot more complex once you need to account for more search parameters and things like different indices. However I believe this solution to be way less error-prone and lighter in terms of bundle size when comparing it to using algolia router.

I hope this helps anyone just trying to get this to work. A proper solution using algolia would still be much appreciated!

Related