Guides / Building Search UI / Going further

Conditional requests with Angular InstantSearch

Angular InstantSearch isn’t compatible with Angular’s Ivy view engine. We’re investigating how best to support this. For more information and to vote for Algolia’s support of Angular 16 and beyond, see the GitHub issue Algolia Support for Angular InstantSearch

By default, InstantSearch sends an initial request to Algolia’s servers with an empty query. This connection helps speed up later requests.

However, sometimes you don’t want to perform more network calls than are necessary. For example, you may want to limit the number of search requests and reduce your overall Algolia usage. This guide helps you build a UI that prevents this initial request.

How a search client works

InstantSearch is the UI layer that sits on top of Algolia’s search client layer, with a state managed by the Algolia search helper layer. These three layers are interchangeable so that you can use the InstantSearch widgets with a different search client.

The search client queries Algolia’s servers whenever users refines a search. You can build a custom search client to add custom behavior. For example, to perform backend searches with InstantSearch.

Implementing a proxy

To prevent the initial empty query, you must wrap a custom search client around Algolia’s, and pass it to ais-instantsearch. The custom search client acts as a proxy for search requests:

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
import { Component } from '@angular/core';
import algoliasearch, { type SearchClient } from 'algoliasearch/lite';

const algoliaClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey'
);

const searchClient: SearchClient = {
  ...algoliaClient,
  search(requests) {
    return algoliaClient.search(requests);
  },
};

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  public config = {
    indexName: 'instant_search',
    searchClient,
  };
}
1
2
3
4
<ais-instantsearch [config]="config">
  <ais-search-box></ais-search-box>
  <ais-hits></ais-hits>
</ais-instantsearch>

This proxy lets you add some logic before calling the search method. In this case, you only call it when performing a query.

Detecting empty search requests

If you don’t want to perform a search request when the query is empty (""), you first need to detect it:

1
2
3
4
5
6
7
8
9
10
const searchClient = {
  ...algoliaClient,
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      // Here we have to do something else
    }

    return algoliaClient.search(requests);
  },
};

Sometimes, one user action results in multiple queries, for example, clicking on an ais-refinement-list or using multiple ais-index widgets. Make sure that every query is empty before intercepting the function call.

When an empty search is detected, you must return a formatted response as an array of objects of the same length as the requests array. Each object requires at least these properties: hits, nbHits, and processingTimeMS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const searchClient = {
  ...algoliaClient,
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      return Promise.resolve({
        results: requests.map(() => ({
          hits: [],
          nbHits: 0,
          nbPages: 0,
          page: 0,
          processingTimeMS: 0,
          hitsPerPage: 0,
          exhaustiveNbHits: false,
          query: '',
          params: '',
        })),
      });
    }

    return algoliaClient.search(requests);
  },
};

Now you can use the proxy with the ais-instantsearch widget, like this:

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
import { Component } from '@angular/core';
import algoliasearch from 'algoliasearch/lite';

const algoliaClient = algoliasearch(
  'YourApplicationID',
  'YourSearchOnlyAPIKey'
);

const searchClient = {
  ...algoliaClient,
  search(requests) {
    if (requests.every(({ params }) => !params.query)) {
      return Promise.resolve({
        results: requests.map(() => ({
          hits: [],
          nbHits: 0,
          nbPages: 0,
          page: 0,
          processingTimeMS: 0,
          hitsPerPage: 0,
          exhaustiveNbHits: false,
          query: '',
          params: '',
        })),
      });
    }

    return algoliaClient.search(requests);
  },
};

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  public config = {
    indexName: 'instant_search',
    searchClient,
  };
}
1
2
3
4
<ais-instantsearch [config]="config">
  <ais-search-box></ais-search-box>
  <ais-hits></ais-hits>
</ais-instantsearch>
Did you find this page helpful?