UI libraries / Algolia for Flutter / Widgets
Signature
HitsSearcher(
  String applicationID,
  String apiKey,
  String indexName,
  // Optional parameters
  bool disjunctiveFacetingEnabled,
  Duration debounce,
)

HitsSearcher.create(
  String applicationID,
  String apiKey,
  SearchState state,
  // Optional parameters
  bool disjunctiveFacetingEnabled,
  Duration debounce,
)

FacetSearcher(
  String applicationID,
  String apiKey,
  String indexName,
  String facet,
  // Optional parameters
  Duration debounce,
)

FacetSearcher.create(
  String applicationID,
  String apiKey,
  FacetSearchState state,
  // Optional parameters
 Duration debounce,
)

MultiSearcher(
  String applicationID,
  String apiKey,
  // Optional parameters
  EventTracker eventTracker
)

About this widget

This component handles search requests and manages search sessions.

HitsSearcher component has the following behavior:

  • Distinct state changes (including initial state) will trigger a search operation
  • State changes are debounced
  • On a new search request, any previous ongoing search calls will be cancelled

Algolia for Flutter comes with these searchers:

  • HitsSearcher: searches a single index.
  • FacetSearcher: searches for facet values.
  • MultiSearcher: aggregates the hits and facet searchers. This is useful for building a federated search, or query suggestions.

Examples

  1. Create a HitsSearcher
  2. Update search state with query and applyState
  3. Listen to search responses and build the UI
  4. dispose of underlying resources
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
52
53
54
55
class SearchScreen extends StatefulWidget {
  const SearchScreen({super.key});

  @override
  State<SearchScreen> createState() => _SearchScreenState();
}

class _SearchScreenState extends State<SearchScreen> {
  // 1. Create a Hits Searcher
  final hitsSearcher = HitsSearcher(
    applicationID: 'YourApplicationID',
    apiKey: 'YourSearchOnlyApiKey',
    indexName: 'YourIndexName',
  );

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          // 2. Run your search operations
          title: TextField(
            onChanged: (input) => hitsSearcher.query(input),
            decoration: const InputDecoration(
              hintText: 'Search...',
              prefixIcon: Icon(Icons.search),
              fillColor: Colors.white,
              filled: true,
            ),
          ),
        ),
        // 3.1 Listen to search responses
        body: StreamBuilder<SearchResponse>(
          stream: hitsSearcher.responses,
          builder: (_, snapshot) {
            if (snapshot.hasData) {
              final response = snapshot.data;
              final hits = response?.hits.toList() ?? [];
              // 3.2 Display your search hits
              return ListView.builder(
                itemCount: hits.length,
                itemBuilder: (_, i) => ListTile(title: Text(hits[i]['title'])),
              );
            } else {
              return const Center(child: CircularProgressIndicator());
            }
          },
        ),
      );

  @override
  void dispose() {
    super.dispose();
    // 4. Release underling resources
    hitsSearcher.dispose();
  }
}

HitsSearcher

applicationID
type: String
Required

The ID of your application.

1
2
3
4
5
final hitsSearcher = HitsSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
);
apiKey
type: String
Required

Your application’s Search-only API key.

1
2
3
4
5
final hitsSearcher = HitsSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
);
indexName
type: String
Required

The index to search into.

1
2
3
4
5
final hitsSearcher = HitsSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
);
state
type: SearchState
Required

Initial search state.

1
2
3
4
5
final hitsSearcher = HitsSearcher.create(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  state: const SearchState(indexName: 'YourIndexName'),
);
disjunctiveFacetingEnabled
type: bool
default: true
Optional

Is disjunctive faceting enabled?

1
2
3
4
5
6
final hitsSearcher = HitsSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  disjunctiveFacetingEnabled: true,
);
debounce
type: Duration
default: Duration(milliseconds: 100)
Optional

Search operation debounce duration.

1
2
3
4
5
6
final hitsSearcher = HitsSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  debounce: const Duration(milliseconds: 100),
);

Fields

responses
type: Stream<SearchResponse>

Stream of search responses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
StreamBuilder<SearchResponse>(
  stream: hitsSearcher.responses,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      final response = snapshot.data!;
      return Column(
        children: [
          Text('${response.nbHits} hits found'),
          ListView.builder(
            itemCount: response.hits.length,
            itemBuilder: (context, index) {
              final hit = response.hits[index];
              return ListTile(title: Text(hit['name']));
            },
          ),
        ],
      );
    } else {
      return const CircularProgressIndicator();
    }
  },
);
state
type: Stream<SearchState>

Stream of search states

1
2
3
4
5
6
7
8
9
10
11
StreamBuilder<SearchState>(
  stream: searcher.state,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      final query = snapshot.data?.query ?? '';
      return Text('Query: $query');
    } else {
      return const CircularProgressIndicator();
    }
  },
);
eventTracker
type: HitsEventTracker

HitsEventTracker instance responsible for handling and sending user events related to search interactions, such as clicks, conversions, and views. These events help to personalize the user’s search experience by providing insights into user behavior. eventTracker is automatically integrated with the HitsSearcher to track events when users interact with the search results.

1
2
3
4
5
hitsSearcher.eventTracker.clickedObjects(
  indexName: 'YourIndexName',
  objectIDs: ['objectID1', 'objectID2'],
  eventName: 'your_event_name',
);

Methods

query

Triggers a search operation with given search query

1
hitsSearcher.query('book');
applyState

Applies a search state configuration and triggers a search operation

1
hitsSearcher.applyState((state) => state.copyWith(query: 'book', page: 0));
snapshot

Gets the latest SearchResponse value submitted by responses stream:

1
final response = hitsSearcher.snapshot();
dispose

Releases all underlying resources

1
hitsSearcher.dispose();

FacetSearcher

applicationID
type: String
Required

The ID of your application.

1
2
3
4
5
6
final facetSearcher = FacetSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  facet: 'facet_attribute',
);
apiKey
type: String
Required

Your application’s Search-only API key.

1
2
3
4
5
6
final facetSearcher = FacetSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  facet: 'facet_attribute',
);
indexName
type: String
Required

The index to search into.

1
2
3
4
5
6
final facetSearcher = FacetSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  facet: 'facet_attribute',
);
facet
type: String
Required

The facet name to search into when doing search for facet values.

1
2
3
4
5
6
final facetSearcher = FacetSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  facet: 'facet_attribute',
);
state
type: FacetSearchState
Required

Initial facet search state.

1
2
3
4
5
6
7
8
final facetSearcher = FacetSearcher.create(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  state: FacetSearchState(
    searchState: SearchState(indexName: 'YourIndexName'),
    facet: 'facet_attribute',
  ),
);
debounce
type: Duration
default: Duration(milliseconds: 100)
Optional

Search operation debounce duration.

1
2
3
4
5
6
7
final facetSearcher = FacetSearcher(
  applicationID: 'YourApplicationID',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  facet: 'facet_attribute',
  debounce: const Duration(milliseconds: 100),
);

Fields

responses
type: Stream<FacetSearchResponse>

Stream of search responses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
StreamBuilder<FacetSearchResponse>(
  stream: facetSearcher.responses,
  builder: (BuildContext context,
      AsyncSnapshot<FacetSearchResponse> snapshot) {
    if (snapshot.hasData) {
      final response = snapshot.data;
      final facets = response?.facetHits.toList() ?? [];
      return ListView.builder(
        itemCount: facets.length,
        itemBuilder: (BuildContext context, int index) {
          final facet = facets[index];
          return ListTile(
            title: Text(facet.value)
          );
        },
      );
    } else {
      return const CircularProgressIndicator();
    }
  },
)
state
type: Stream<FacetSearchState>

Stream of facet search states

1
2
3
4
5
6
7
8
9
10
11
StreamBuilder<FacetSearchState>(
  stream: searcher.state,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      final query = snapshot.data?.facetQuery ?? '';
      return Text('Facet query: $query');
    } else {
      return const CircularProgressIndicator();
    }
  },
);

Methods

query

Triggers a search operation with given search query

1
facetSearcher.query('book');
applyState

Applies a search state configuration and triggers a search operation

1
facetSearcher.applyState((state) => state.copyWith(facetQuery: 'book'));
snapshot

Gets the latest FacetSearchResponse value submitted by responses stream:

1
final response = facetSearcher.snapshot();
dispose

Releases all underlying resources

1
facetSearcher.dispose();

MultiSearcher

strategy
type: MultipleQueriesStrategy
default: None
Optional

MultiSearcher lets you simultaneously search for hits and facet values in different indices of the same Algolia application. It instantiates and manages HitsSearcher and FacetSearcher instances. Once created, these searchers behave like their independently instantiated counterparts.

1
2
3
4
5
final multiSearcher = MultiSearcher(
    applicationID = ApplicationID("YourApplicationID"),
    apiKey = APIKey("YourSearchOnlyApiKey"),
    eventTracker: Insights('MY_APPLICATION_ID', 'MY_API_KEY'),
)

Methods

dispose

Releases all underlying resources

1
multiSearcher.dispose();
addHitsSearcher

Adds a new HitsSearcher to the multi-searcher.

1
2
3
4
5
final hitsSearcher = multiSearcher.addHitsSearcher(
  initialState: const SearchState(
    indexName: 'instant_search',
  ),
);
addFacetSearcher

Adds a new FacetSearcher to the multi-searcher.

1
2
3
4
5
6
7
8
final facetSearcher = multiSearcher.addFacetSearcher(
    initialState: const FacetSearchState(
      facet: 'brand',
      searchState: SearchState(
        indexName: 'instant_search',
      ),
    )
);
Did you find this page helpful?