Flutter DropdownButton - populate items from rest webservice

5,188

Solution 1

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, ...

Solution 2

      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();

Solution 3

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.

Share:
5,188
user1209216
Author by

user1209216

Updated on December 09, 2022

Comments

  • user1209216
    user1209216 over 1 year

    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?

  • user1209216
    user1209216 about 5 years
    Wy not use FutureBuilder? I managed to obtain future cities list in initState (by calling my fetchCities method, then passed retrieved list to FutureBuilder and no it works.
  • Victor Godoy
    Victor Godoy about 5 years
    @user1209216 Follow this answer and check that value: from DropdownMenuItem must be some kind of id, something to compare you can't compare a Object like you are doing in the question.
  • user1209216
    user1209216 about 5 years
    I actually see no problems with this approach. Future retrieved in initState, passed to FutureBuilder. I just moved fetchCities to initState