My fetchCities()
method returns Future<List<City>>
and it loads data from rest webservice. Code to populate items:
Widget buildCitiesSelector(){
return new Center(
child: FutureBuilder(
future: fetchCities() ,
builder: (context, snapshot){
if (snapshot.hasData) {
return new DropdownButton <City>(
hint: Text('Wybierz miasto'),
items: snapshot.data.map<DropdownMenuItem<City>>((City value) {
return DropdownMenuItem<City>(
value: value,
child: Text(value.name),
);
}).toList(),
onChanged: (value) {
setState(() {_selectedCity = value;});
},
value: _selectedCity,
);
}
else{
return CircularProgressIndicator();
}
}
)
);
}
Result: items are correctly displayed in selector. However, when selecting any particular item, I'm getting exception:
I/flutter (13910): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter (13910): The following assertion was thrown building FutureBuilder>(dirty, state: I/flutter (13910): _FutureBuilderState>#dacd9): I/flutter (13910): 'package:flutter/src/material/dropdown.dart': Failed assertion: line 560 pos 15: 'items == null || I/flutter (13910): items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value == I/flutter (13910): value).length == 1': is not true.
How to properly select item? Any ideas what's wrong?
You should not use FutureBuilder
for this situation. Rather fetch the data in initState()
and then cause a rebuild using setState()
to update the view.
If fetchCities()
creates a new Future
every time it is called, then build()
will invoke that fetch every time the UI is rebuilt (which can be quite often)
https://docs.flutter.io/flutter/widgets/FutureBuilder-class.html
The future must have been obtained earlier, e.g. during State.initState, ...
child: FutureBuilder(
future: Webservice().load(Country.countries) ,
builder: (context, snapshot){
if(snapshot.hasError)
return Text(snapshot.error);
if (snapshot.hasData) {
return DropdownButtonFormField(
decoration: new InputDecoration(icon: Icon(Icons.language)), //, color: Colors.white10
value: selectedCountry,
items: snapshot.data.map<DropdownMenuItem<Country>>((Country country) {
return DropdownMenuItem<Country>(
value: country,
child: Text(country.name, style: TextStyle(color: Color.fromRGBO(58, 66, 46, .9))),
);
})
.toList(),
onChanged: (Country newValue) {
setState(() => selectedCountry = newValue);
// selectedCountry = newValue;
print(newValue.id);
print(newValue.name);
},
);
}
return CircularProgressIndicator();
I had the same issue today, and after some digging, I found a mistake in my code: the value in the DropdownButton wasn't in the items list.
I assumed (wrongly) that the dropdown would handle the "empty" value - but that is not the case.
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