I need to have Google Places search suggestions using the default flutter's SearchPage, whenever the user starts typing I need to give autocomplete suggestions and I achieve this Asynchronously using FutureBuilder, the problem now is that I need to debounce the dispatch of search requests for 500ms or more rather than wasting a lot of requests while the user is still typing
To summarize what I've done so far:
1) In my widget I call
showSearch(context: context, delegate: _delegate);
2) My delegate looks like this:
class _LocationSearchDelegate extends SearchDelegate<Suggestion> {   
  @override
  List<Widget> buildActions(BuildContext context) {
    return <Widget>[
      IconButton(
        tooltip: 'Clear',
        icon: const Icon(Icons.clear),
        onPressed: () {
          query = '';
          showSuggestions(context);
        },
      )
    ];
  }
  @override
  Widget buildLeading(BuildContext context) => IconButton(
        tooltip: 'Back',
        icon: AnimatedIcon(
          icon: AnimatedIcons.menu_arrow,
          progress: transitionAnimation,
        ),
        onPressed: () {
          close(context, null);
        },
      );
  @override
  Widget buildResults(BuildContext context) {
    return FutureBuilder<List<Suggestion>>(
      future: GooglePlaces.getInstance().getAutocompleteSuggestions(query),
      builder: (BuildContext context, AsyncSnapshot<List<Suggestion>> suggestions) {
        if (!suggestions.hasData) {
          return Text('No results');
        }
        return buildLocationSuggestions(suggestions.data);
      },
    );
  }
  @override
  Widget buildSuggestions(BuildContext context) {
    return buildResults(context);
  }
  Widget buildLocationSuggestions(List<Suggestion> suggestions) {
    return ListView.builder(
      itemBuilder: (context, index) => ListTile(
            leading: Icon(Icons.location_on),
            title: Text(suggestions[index].text),
            onTap: () {
              showResults(context);
            },
          ),
      itemCount: suggestions.length,
    );
  }
}
3-I need to throttle / debounce searching until xxx Milliseconds have passed
I have 1 idea in mind, would there be an easy way to convert FutureBuilder to Stream and Use Stream builder, (which I read in some articles that it supports debouncing)?
**I am aware that there are some 3rd party AutoComplete widgets like TypeAhead that's doing that (from scratch) but I don't wanna use this at the moment.
Here's a simple alternative to the other answer.
import 'package:debounce_throttle/debounce_throttle.dart';
final debouncer = Debouncer<String>(Duration(milliseconds: 250));
Future<List<Suggestion>> queryChanged(String query) async {
  debouncer.value = query;      
  return GooglePlaces.getInstance().getAutocompleteSuggestions(await debouncer.nextValue)
}
  @override
  Widget buildResults(BuildContext context) {
    return FutureBuilder<List<Suggestion>>(
      future: queryChanged(query),
      builder: (BuildContext context, AsyncSnapshot<List<Suggestion>> suggestions) {
        if (!suggestions.hasData) {
          return Text('No results');
        }
        return buildLocationSuggestions(suggestions.data);
      },
    );
  }
That's roughly how you should be doing it I think.
Here are a couple of ideas for using a stream instead, using the debouncer.
void queryChanged(query) => debouncer.value = query;
Stream<List<Suggestion>> get suggestions async* {
   while (true)
   yield GooglePlaces.getInstance().getAutocompleteSuggestions(await debouncer.nexValue);
}
  @override
  Widget buildResults(BuildContext context) {
    return StreamBuilder<List<Suggestion>>(
      stream: suggestions,
      builder: (BuildContext context, AsyncSnapshot<List<Suggestion>> suggestions) {
        if (!suggestions.hasData) {
          return Text('No results');
        }
        return buildLocationSuggestions(suggestions.data);
      },
    );
  }
Or with a StreamTransformer.
Stream<List<Suggestion>> get suggestions => 
  debouncer.values.transform(StreamTransformer.fromHandlers(
    handleData: (value, sink) => sink.add(GooglePlaces.getInstance()
      .getAutocompleteSuggestions(value))));
I Simply did it this way no library required:
void searchWithThrottle(String keyword, {int throttleTime}) {
    _timer?.cancel();
    if (keyword != previousKeyword && keyword.isNotEmpty) {
      previousKeyword = keyword;
      _timer = Timer.periodic(Duration(milliseconds: throttleTime ?? 350), (timer) {
        print("Going to search with keyword : $keyword");
        search(keyword);
        _timer.cancel();
      });
    }
  }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With