Flutter showSearch async operation when building suggestions
Return a FutureBuilder
:
Future<Widget> buildSuggestions(BuildContext context) {
return FutureBuilder(
future: Geocoder.local.findAddressesFromQuery(query),
builder: (BuildContext context, AsyncSnapshot snapshot) {
// check if snapshot.hasData
var addresses = snapshot.data;
final Iterable<Address> suggestions = query.isEmpty
? _history
: addresses;
return _SuggestionList(
query: query,
suggestions: suggestions.map<String>((String i) => '$i').toList(),
onSelected: (String suggestion) {
query = suggestion;
this.close(context, query);
},
);
)
}
FutureBuilder
is built on top of StatefulWidget
. Attempting to solve this problem with a StatefulWidget
is not wrong but simply lower-level and more tedious.
This article explains it in detail: https://flutterigniter.com/build-widget-with-async-method-call/
Comments
-
Jakub over 1 year
I am using the flutter showSearch function to search for addresses. Everything works fine so far. Now I want to implement suggestions that will be rebuild each time the user changes the search input. To do this I am using the flutter geocode library.
The problem is that I don't know how I can execute an async operation when building suggestions using the buildSuggestions function.
Obviously I cannot simple make the buildSuggestions function async, but if I could my code would look like this:
@override Future<Widget> buildSuggestions(BuildContext context) async { var addresses = await Geocoder.local.findAddressesFromQuery(query); final Iterable<Address> suggestions = query.isEmpty ? _history : addresses; return _SuggestionList( query: query, suggestions: suggestions.map<String>((String i) => '$i').toList(), onSelected: (String suggestion) { query = suggestion; this.close(context, query); }, ); }
There must be ways of achieving what I want to do. Any suggestions?
UPDATE:
With the help of the post from frank06 I wrote the following code:
@override Widget buildSuggestions(BuildContext context) { return FutureBuilder( future: Geocoder.local.findAddressesFromQuery(query), builder: (BuildContext context, AsyncSnapshot<List<Address>> snapshot) { // check if snapshot.hasData if (snapshot.connectionState == ConnectionState.done) { List<Address> addresses; if (snapshot.hasData) { addresses = snapshot.data; } else { addresses = List<Address>(); } List<String> addressNames = addresses.map((address) { return address.addressLine; }).toList(); final Iterable<String> suggestions = query.isEmpty ? _history : addressNames; return _SuggestionList( query: query, suggestions: suggestions.map<String>((String i) => '$i').toList(), onSelected: (String suggestion) { query = suggestion; this.close(context, query); }, ); } else { return _SuggestionList( query: query, suggestions: List<String>(), onSelected: (String suggestion) { query = suggestion; this.close(context, query); }); } }); }
I feel like I have gotten a lot closer to the solution, but currently I have the problem that snapshot.hasData always returns false.
Any further suggestions?
FINAL UPDATE:
Finally it did work. My future was not returning data because I hadn't made sure that my query was actually of datatype String. The code below is the final functioning version. (Thanks again to frank06!).
@override Widget buildSuggestions(BuildContext context) { String queryString = query; return FutureBuilder( future: queryString.length > 0 ? Geocoder.local.findAddressesFromQuery(queryString) : Future.value(List<Address>()), builder: (BuildContext context, AsyncSnapshot<List<Address>> snapshot) { if (snapshot.connectionState == ConnectionState.done) { List<Address> addresses; if (snapshot.hasData) { addresses = snapshot.data; } else { addresses = List<Address>(); } List<String> addressNames = addresses.map((address) { return address.addressLine; }).toList(); final Iterable<String> suggestions = query.isEmpty ? _history : addressNames; return _SuggestionList( query: query, suggestions: suggestions.map<String>((String i) => '$i').toList(), onSelected: (String suggestion) { query = suggestion; this.close(context, query); }, ); } else { return _SuggestionList( query: query, suggestions: List<String>(), onSelected: (String suggestion) { query = suggestion; this.close(context, query); }); } }); }
-
Jakub over 4 yearsHey frank, thank you for your post! I see what you are suggesting. I think it might work, atm I am just having the problem that snapshot.hasData always returns false.
-
Frank Treacy over 4 yearsYou're welcome Jakub, did you check
hasError
? is your future actually working? -
Frank Treacy over 4 years@Jakub try
future: Future.value([Address(), Address()])
(e.g. two dummy addresses) and if that does work withsnapshot.data
then the problem is with your future -
Jakub over 4 yearsThank you again, you have been very helpful! The problem was, that my future did not actually return any data, because the "query" was not of type String. After I had casted the query to String everything worked perfectly (: