Concepts / Building Search UI / Conditional display
Apr. 17, 2019

Conditional Display

You are reading the documentation for Vue InstantSearch v2. Read our migration guide to learn how to upgrade from v1 to v2. You can still find the v1 documentation here.

Handling no results

When a query returns no results, it is important to let the user know that their query led to no results.

By doing so, the UI acknowledges that not all queries lead to some result and with some additional hints you can let them continue to use the search. This way, there is less chance that the user will leave the website to do a search on an external search engine.

There are various strategies that can be implemented for the no-result. This guide will walk you through one that can be easily implemented with InstantSearch.js:

  • first you will improve the message that you provide to the user
  • then you will add a button to let the user clear the filters

Display a message

By default, InstantSearch will only display “no results” when there are no results. The bare minimum to handle the no-result case is to provide the user with a message that indicates that no results were found in a friendly fashion.

In order to do that, you can use the ais-state-results widget option to detect if there are no hits:

1
2
3
4
5
6
7
8
9
10
<ais-state-results>
  <template slot-scope="{ hits }">
    <ais-hits v-if="hits.length > 0">
      <!-- customize your hits as usual -->
    </ais-hits>
    <div v-else>
      There are no hits found for: <q>{{query}}</q>
    </div>
  </template>
</ais-state-results>

When there are no results, the user will see a paragraph that says: “There are no hits found for: the current query”.

Let the user clear all the filters

To go further, you can also let the user clear the filters and start their search from scratch. This way, you allow the user to make mistake.

In Vue InstantSearch it’s possible to use the <ais-clear-refinement> widget to add a button to clear the refinements if there are no hits. Note that we will add :excluded-attributes="[]" to make sure the query will also be cleared, since it is not cleared by default. This is done similarly to the previous situation:

1
2
3
4
5
6
7
8
9
10
11
12
13
<ais-state-results>
  <template slot-scope="{ hits }">
    <ais-hits v-if="hits.length > 0">
      <!-- customize your hits as usual -->
    </ais-hits>
    <div v-else>
      There are no hits found for: <q>{{query}}</q>.
      <ais-clear-refinements :excluded-attributes="[]">
        <template slot="resetLabel">Clear the refinements</template>
      </ais-clear-refinements>
    </div>
  </template>
</ais-state-results>

As another option you can also use <ais-current-refinements :excluded-attributes="[]"> to show the currently applied refinements like this:

1
2
3
4
5
6
7
8
9
10
11
<ais-state-results>
  <template slot-scope="{ hits }">
    <ais-hits v-if="hits.length > 0">
      <!-- customize your hits as usual -->
    </ais-hits>
    <div v-else>
      There are no hits found for: <q>{{query}}</q>.
      <ais-current-refinements :excluded-attributes="[]" />
    </div>
  </template>
</ais-state-results>

Handling empty query

When you want to hide the results (or do something else) if the query is empty, you can use the <ais-state-results> component. You can use the scoped slot to, for example, hide all the results if there’s no query:

1
2
3
4
5
6
7
<ais-state-results>
  <template slot-scope="{ query }">
    <ais-hits v-if="query.length > 0">
      <!-- customize your hits as usual -->
    </ais-hits>
  </template>
</ais-state-results>

Note that for reasons like accessibility, it might be better to use a real autocomplete component, like <vue-autocomplete>. You can use that as follows:

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>
  <div>
    <ais-autocomplete>
      <template slot-scope="{currentRefinement, indices, refine}">
        <vue-autosuggest
          :suggestions="indicesToSuggestions(indices)"
          :on-selected="onSelect"
          :input-props="{
            style: 'width: 100%',
            onInputChange: refine,
          }"
        >
          <template slot-scope="{ suggestion }">
            <img :src="suggestion.item.image" style="width: 50px;"/>
            <span>
              <ais-highlight
                :hit="suggestion.item"
                attribute="name"
                v-if="suggestion.item.name"
              />
              <strong>$ {{ suggestion.item.price }}</strong>
            </span>
          </template>
        </vue-autosuggest>
      </template>
    </ais-autocomplete>
    <details v-if="selected">
      <summary><code>selected item</code></summary>
      <pre>{{selected.item}}</pre>
    </details>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selected: undefined,
    };
  },
  methods: {
    onSelect(selected) {
      this.selected = selected;
    },
    indicesToSuggestions(indices) {
      return indices.map(({ hits }) => ({ data: hits }));
    },
  },
};
</script>

Did you find this page helpful?