Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make dependent multilevel DropDown in flutter?

I am trying to make dependent multilevel dropdown first contains states list and second contains cities list, all the data fetched from API. Initially, I load state dropdown, when I select the state then cities of that state load if I select city, the city selected successfully but when I change the state value then an error occurs. What is the right way to reload the second dropdown if changes will make in the first dropdown?

Error: There should be exactly one item with [DropdownButton]'s value: Instance of 'City'. Either zero or 2 or more [DropdownMenuItem]s were detected with the same value

Future _state;
Future _city;

@override
  void initState() {
    super.initState();
    _state = _fetchStates();
  }
Future<List<StateModel>> _fetchStates() async {
    final String stateApi = "https://dummyurl/state.php";
    var response = await http.get(stateApi);

    if (response.statusCode == 200) {
      final items = json.decode(response.body).cast<Map<String, dynamic>>();

      List<StateModel> listOfUsers = items.map<StateModel>((json) {
        return StateModel.fromJson(json);
      }).toList();

      return listOfUsers;
    } else {
      throw Exception('Failed to load internet');
    }
  }
  Future<List<City>> _fetchCities(String id) async {
    final String cityApi = "https://dummyurl/city.php?stateid=$id";
    var response = await http.get(cityApi);

    if (response.statusCode == 200) {
      final items = json.decode(response.body).cast<Map<String, dynamic>>();
      print(items);
      List<City> listOfUsers = items.map<City>((json) {
        return City.fromJson(json);
      }).toList();

      return listOfUsers;
    } else {
      throw Exception('Failed to load internet');
    }
  }

State Dropdown

FutureBuilder<List<StateModel>>(
                                        future: _state,
                                        builder: (BuildContext context,
                                            AsyncSnapshot<List<StateModel>> snapshot) {
                                          if (!snapshot.hasData)
                                            return CupertinoActivityIndicator(animating: true,);
                                          return DropdownButtonFormField<StateModel>(
                                            isDense: true,
                                            decoration: spinnerDecoration('Select your State'),
                                            items: snapshot.data
                                                .map((countyState) => DropdownMenuItem<StateModel>(
                                              child: Text(countyState.billstate),
                                              value: countyState,
                                            ))
                                                .toList(),
                                            onChanged:(StateModel selectedState) {
                                              setState(() {
                                                stateModel = selectedState;
                                                _city = _fetchCities(stateModel.billstateid);
                                              });
                                            },
                                            value: stateModel,
                                          );
                                        }),

City Dropdown

FutureBuilder<List<City>>(
                                        future: _city,
                                        builder: (BuildContext context,
                                            AsyncSnapshot<List<City>> snapshot) {
                                          if (!snapshot.hasData)
                                            return CupertinoActivityIndicator(animating: true,);
                                          return DropdownButtonFormField<City>(
                                            isDense: true,
                                            decoration: spinnerDecoration('Select your City'),
                                            items: snapshot.data
                                                .map((countyState) => DropdownMenuItem<City>(
                                              child: Text(countyState.billcity)
                                                .toList(),
                                            onChanged: (City selectedValue) {
                                              setState(() {
                                                cityModel = selectedValue;
                                              });
                                            },
                                            value: cityModel,
                                          );
                                        }),
class StateModel {
  String billstateid;
  String billstate;
  String billcountryid;

  StateModel({this.billstateid, this.billstate, this.billcountryid});

  StateModel.fromJson(Map<String, dynamic> json) {
    billstateid = json['billstateid'];
    billstate = json['billstate'];
    billcountryid = json['billcountryid'];
  }
}
class City {
  String billcityid;
  String billcity;
  String billstateid;

  City({this.billcityid, this.billcity, this.billstateid});

  City.fromJson(Map<String, dynamic> json) {
    billcityid = json['billcityid'];
    billcity = json['billcity'];
    billstateid = json['billstateid'];
  }
like image 287
Jorden Avatar asked Feb 27 '20 12:02

Jorden


People also ask

What is dropdown flutter?

DropDownButton: In Flutter, A DropDownButton is a material design button. The DropDownButton is a widget that we can use to select one unique value from a set of values. It lets the user select one value from a number of items. The default value shows the currently selected value.


1 Answers

You have to make cityModel = null in onChanged callback of State dropdown.

setState(() {
  cityModel = null;
  stateModel = selectedState;
  _city = _fetchCities(stateModel.billstateid);
});

There should be exactly one item with [DropdownButton]'s value: Instance of 'City'. Either zero or 2 or more [DropdownMenuItem]s were detected with the same value

This error occurs here, because the value you are passing not in the items of DropdownButtonFormField(city dropdown).

When you select a State, you are fetching new list of city list and passing it to CityDropDown but forgot to clear the previously selected city(cityModel).

You can also refer this example: DartPad

like image 70
Crazy Lazy Cat Avatar answered Sep 21 '22 08:09

Crazy Lazy Cat