algolia / algolia/algoliasearch-helper-flutter

How to display facets with count

Open
#29 8 comments 0 reactions 0 assignees View on GitHub
question
Dominant language
Dart
Stars
27
Forks
21
Avg merge
1h 19m
Merged PRs (30d)
1

Description

I'm trying to get the list of facet that I've configured as describe [here](https://www.algolia.com/doc/guides/building-search-ui/ui-and-ux-patterns/facet-display/js/?client=javascript). I use the new official Algolia package along with the unofficial for settings. I thought that use the official package would change the response. Despite in the console browser every thing is display as attended, the searchResponse.facets is always empty. Check the code below.
```import 'dart:async';
import 'dart:io';

import 'package:algolia/algolia.dart';
import 'package:algolia_helper_flutter/algolia_helper_flutter.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:masterecommerce/src/constants/app_sizes.dart';
import 'package:masterecommerce/src/exceptions/app_exception.dart';
import 'package:masterecommerce/src/features/menu/presentation/search_header.dart';
import 'package:masterecommerce/src/features/products/domain/algolia_output.dart';
import 'package:masterecommerce/src/features/products/domain/algolia_params.dart';

import '../constants/credentials.dart';
import '../features/products/domain/product.dart';
import 'firestore_service.dart';

final searchResponseProvider = StateProvider.autoDispose((ref) {
return SearchResponse({});
});
final searchStateProvider = StateProvider.autoDispose((ref) {
return const SearchState(indexName: kIndexName);
});
final algoliaInputProvider = StateProvider.autoDispose((ref) {
return const AlgoliaInput();
});

final algoliaControllerProvider = StateNotifierProvider.autoDispose<
AlgoliaController, AsyncValue>>((ref) {
return AlgoliaController(
ref: ref, algoliaInput: ref.watch(algoliaInputProvider));
});

final algoliaControllerSearchProvider = StateNotifierProvider.autoDispose<
AlgoliaController, AsyncValue>>((ref) {
return AlgoliaController(
ref: ref,
algoliaInput: AlgoliaInput(
query: ref.watch(currentQuerySearchProvider), hitsPerPage: 3));
});

class AlgoliaController extends StateNotifier>> {
StreamSubscription? subResponses;
StreamSubscription? subSearchState;

late HitsSearcher searcher;
late Algolia algoliaForSettings;
final Ref ref;
final AlgoliaInput algoliaInput;

AlgoliaController({required this.ref, required this.algoliaInput})
: super(const AsyncLoading()) {
algoliaForSettings = const Algolia.init(
applicationId: algoliaKeyAppId, apiKey: algoliaKeyCustom);
searcher = HitsSearcher(
applicationID: algoliaKeyAppId,
apiKey: algoliaKeyCustom,
indexName: kIndexName,
);

subResponses = searcher.responses.handleError((onError) {
print(onError);
state = AsyncError(onError);
}).listen((searchResponse) {
print(searchResponse.facets);
print(searchResponse.raw["facets"]);
ref.read(searchResponseProvider.state).update((state) => searchResponse);

final products = searchResponse.hits
.map((e) => Product.fromMapAlgolia(e.cast()))
.toList();
if (mounted) {
state = AsyncValue>.data(products);
}
});

subSearchState = searcher.state.handleError((onError) {
print(onError);
state = AsyncError(onError);
}).listen((searchState) {
ref.read(searchStateProvider.state).update((state) => searchState);
});

_newAlgoliaState(algoliaInput: algoliaInput);
}

@override
void dispose() {
searcher.dispose();
subResponses?.cancel();
subSearchState?.cancel();
super.dispose();
}

Future _newAlgoliaState({required AlgoliaInput algoliaInput}) async {
state = const AsyncLoading();

final algoliaOutput = algoliaInput.toAlgoliaOutput();
await _setAlgoliaRanking(algoliaOutput: algoliaOutput);
if (!mounted) {
return;
}
searcher.connectFilterState(algoliaOutput.filterState);
searcher.applyState((state) => algoliaOutput.toSearchState());
}

Future _setAlgoliaRanking(
{required AlgoliaOutput algoliaOutput}) async {
AlgoliaIndexReference algoliaIndexReference =
algoliaForSettings.instance.index("products");
final ranking = algoliaOutput.ranking;
if (ranking != null && ranking.isNotEmpty) {
AlgoliaTask algoliaTask =
await algoliaIndexReference.settings.setRanking([
...ranking,
"typo",
"geo",
"words",
"filters",
"proximity",
"attribute",
"exact",
"custom",
]).setSettings();

await algoliaTask
.waitTask()
.timeout(const Duration(seconds: timeOutSecond))
.catchError((onError) {
if (onError is SocketException) {
throw const AppException.noInternet();
} else if (onError is TimeoutException) {
throw const AppException.timeOut();
} else {
throw const AppException.unknown();
}
});
}

final customRanking = algoliaOutput.customRanking;

if (customRanking != null && customRanking.isNotEmpty) {
final AlgoliaTask algoliaTask = await algoliaIndexReference.settings
.setCustomRanking(customRanking)
.setSettings();

await algoliaTask
.waitTask()
.timeout(const Duration(seconds: timeOutSecond))
.catchError((onError) {
if (onError is SocketException) {
throw const AppException.noInternet();
} else if (onError is TimeoutException) {
throw const AppException.timeOut();
} else {
throw const AppException.unknown();
}
});
}
}
}

```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the response from the searcher.responses listener and inspect SearchResponse.facets alongside raw["facets"]. Trace the state setup through _newAlgoliaState, connectFilterState, and applyState, and compare it with the Algolia index settings configured in _setAlgoliaRanking. Done means configured facets and their counts are available in the search response.

Written by the indexing model from the issue text.

Assessment

Tech stack
dart, flutter
Domain
mobile-dev, search
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.