I love Algolia's search service, which makes it so easy to implement search functionality on any site.

On a recent site I was using the Vue InstantSearch component, which is basically a wrapper around the Algolia api in the form of a Vue component.

What's the problem? No page refresh.

It was super easy to setup, but the only problem I had was that I wanted to clear / reset the search box whenever the user selected a search result.

I'm guessing that usually this isn't a problem for most users since clicking on a search result would usually be a link to a specific page where the page would have been refreshed and the Vue component re-initialized.

My problem was that I had this integrated with a NuxtJS site, where the nuxt-link component dynamically changes the page contents without actually refreshing the page in the browser. This meant that the Vue component was not reset, while the user navigated to a different page and the search results were still visible!

Here's what I mean:

You'll notice the user has selected a search result and the page content has changed, but the search bar and results are still showing the old results - bleh!

What I wanted to do was have the search results reset when any result was selected, a much nicer user experience :)

Existing solutions were ugly

It's unfortunate that the Vue Instant Search component didn't offer a simple prop to reset the component, and Algolia engineers recommended a somewhat clunky solution. Basically they recommended including the ais-clear-refinements component, which adds a button which the user would have to click to clear the result.

Maybe it was good enough for the folks who raised issues for it here and here, but I really didn't like this.

My solution

I got it working by adding a click event handler on the search result, which then called a custom method I wrote to clear the results. It's not the prettiest and is certainly not the "reactive" way to build this, but it was the best option available when the component does not expose the props I needed.

Here's what it looks like:

  

# SearchBar.vue component
<template>
  <ais-instant-search
    :search-client="searchClient"
    :index-name="myIndex"
  >
      <ais-search-box placeholder="Search articles..." />

      <ais-hits ref="searchHits">
        <template slot="item" slot-scope="{ item }">
          <nuxt-link
            :to="'/article/' + item.fields.slug['en-US']"
            @click.native="resetSearch"
          >
            <ais-highlight attribute="fields.title.en-US" :hit="item" />
          </nuxt-link>
        </template>
      </ais-hits>
  </ais-instant-search>
</template>

<script>
import algoliasearch from 'algoliasearch/lite'

import {
  AisInstantSearch,
  AisHits,
  AisHighlight,
  AisSearchBox,
  AisStateResults,
} from 'vue-instantsearch'

const searchClient = algoliasearch("MY_APP_ID", "MY_API_KEY")

export default {
  components: {
    AisInstantSearch,
    AisHits,
    AisHighlight,
    AisSearchBox,
    AisStateResults,
  },
  data() {
    return {
      searchClient,
    }
  },
  methods: {
    resetSearch() {
      // clear the search input. I have multiple b/c I have a different one for mobile.
      document
        .querySelectorAll('.ais-SearchBox-input')
        .forEach((e) => (e.value = ''))

      // clear all the hits
      document.querySelectorAll('.ais-Hits-item').forEach((e) => e.remove())

      // also clear the hits from the component, otherwise subsequent searches throw exceptions
      this.$refs.searchHits.state.hits = []
    },
  },
}
</script>

  

The results

Here's how it looks now: