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 # A

This component is the main entry point for Flutter Helpers: it 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 # A

  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: 'AJ0P3S7DWQ',
    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 # A

Parameter Description
applicationID #
type: String
Required

The ID of your application.

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

Your application’s Search-only API key.

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

The index to search into.

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

Initial search state.

1
2
3
4
5
final hitsSearcher = HitsSearcher.create(
  applicationID: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  debounce: const Duration(milliseconds: 100),
);

Fields # A

Parameter Description
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 # A

Parameter Description
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 # A

Parameter Description
applicationID #
type: String
Required

The ID of your application.

1
2
3
4
5
6
final facetSearcher = FacetSearcher(
  applicationID: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  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: 'AJ0P3S7DWQ',
  apiKey: 'YourSearchOnlyApiKey',
  indexName: 'YourIndexName',
  facet: 'facet_attribute',
  debounce: const Duration(milliseconds: 100),
);

Fields # A

Parameter Description
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 # A

Parameter Description
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 # A

Parameter Description
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("AJ0P3S7DWQ"),
    apiKey = APIKey("YourSearchOnlyApiKey"),
    eventTracker: Insights('MY_APPLICATION_ID', 'MY_API_KEY'),
)

Methods # A

Parameter Description
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?