'Multiple Dependent dropdown in flutter

I am trying to build multiple dependent dropdown on flutter. The second one depend on 1st one. here is the code to the dropdown I have implemented.

Container(
            child: new DropdownButton<String>(
              underline: SizedBox(
                height: 1,
              ),
              hint: new Text("Select Faculty"),
              value: facultyId,
              items: faculty.map((item) {
                return new DropdownMenuItem(
                  child: new Text(item['name']),
                  value: item['id'].toString(),
                );
              }).toList(),
              onChanged: (faculty == null)
                  ? null
                  : (String newValue) {
                      setState(() {
                        filteredbatch.clear();
                        facultyId = newValue;
                        for (var item in allbatch) {
                          if (item['facultyId'].toString() == newValue){
                          filteredbatch.add(item);
                            disableBatch = false;
                          }
                        }
                      });
                      print(facultyId);
                    },
            ),
          ),
          Container(
            child: new DropdownButton<String>(
                underline: SizedBox(
                  height: 1,
                ),
                disabledHint: new Text("Select Faculty First"),
                hint: Text("Select Batch"),
                value: batchId,
                onChanged: disableBatch
                    ? null
                    : (String newValue) {
                        setState(() {
                          batchId = newValue;
                          disableSection = false;
                        });
                        print(batchId);
                      },
                items: filteredbatch.map((item) {
                  return DropdownMenuItem(
                    child: Text(item['name']),
                    value: item['id'].toString(),
                  );
                }).toList()),
          ),

Whenever I select one dropdown item from first one, it enables 2nd dropdown and lets me to select an item from that dropdown. And when I select an item from 2nd dropdown and go back to change first dropdown, it throws error that dropdown requires one item with respective value. 0 or 2 found. I am lost here. How do I resolve this error?



Solution 1:[1]

What is going on here is quite simple. Let's say "allbatch" has these values:

faculty: foo , which has batchids: foo1, foo2, foo3

faculty: bar , which has batchids: bar1, bar2, bar3.

When you select foo in the 1st dropdown a new "filteredbatch" is created and it only contains foo1,foo2,foo3. You then select foo3 in your 2nd dropdown and everything is still working fine...

BUT when you change your 1st dropdown to bar, then "filteredbatch" only contains:bar1, bar2, bar3 and your second dropdown value is still set to foo3 which can not be found in the newly generated "filteredbatch", and then you get that error you are seeing.

To fix this simply set batchId to null before changing the "filteredbatch" in your 1st dropdown onChanged method:

  setState(() {
    //fix
    batchId = null;
    //end of fix
    filteredbatch.clear();
    facultyId = newValue;
    for (var item in allbatch) {
      if (item['facultyId'].toString() == newValue){
      filteredbatch.add(item);
        disableBatch = false;
      }
    }
  });

Your 2nd dropdown will revert back to hint text and the app user will have to select a new batchId.

If you have any more questions feel free to ask.

Solution 2:[2]

Flutter Dropdown Button FormField Dependent

List<String> dataList = ["A", "B", "C"];
    List<String> dataListA = ["A1", "A2", "A3", "A4", "A5"];
    List<String> dataListB = ["B1", "B2", "B3", "B4", "B5"];
    List<String> dataListC = ["C1", "C2", "C3", "C4", "C5"];
    
    String? valueItem;
    List<String> listItem = [];


// DropdownButtonFormField
Container(
  margin: const EdgeInsets.only(bottom: p20),
  child: DropdownButtonFormField<String>(
  decoration: InputDecoration(
  labelText: 'Data list',
  labelStyle: const TextStyle(),
  border: OutlineInputBorder(
  borderRadius: BorderRadius.circular(5.0)),
  contentPadding: const EdgeInsets.only(left: 5.0),),
  value: valueItem,
  isExpanded: true,
  items: dataList.map((String value) {
   return DropdownMenuItem<String>(
   value: value,
  child: Text(value),);
 }).toSet().toList(),
  onChanged: (value) {
   setState(() {
         valueItem= value!;
       if (valueItem=="A") {
          listItem= dataListA;
      } else if (valueItem== "B") {
         listItem= dataListB;
      } else if (valueItem== "C") {
      listItem= dataListC;
    }
  });
},

), ),

// Second DropdownButtonFormField
Container(
  margin: const EdgeInsets.only(bottom: p20),
  child: DropdownButtonFormField<String>(
  decoration: InputDecoration(
  labelText: 'List dependent',
  labelStyle: const TextStyle(),
  border: OutlineInputBorder(
  borderRadius: BorderRadius.circular(5.0)),
  contentPadding: const EdgeInsets.only(left: 5.0),),
  value: ListItem,
  isExpanded: true,
  items: listItem.map((String value) {
   return DropdownMenuItem<String>(
    value: value,
    child: Text(value),
  );}).toSet().toList(),
  onChanged: (value) {
   setState(() {
     your_value = value!;
  });
 },

), ),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Uroš
Solution 2