Emir Bolat
Emir Bolat

Reputation: 57

Flutter - Show options on the second DropdownButton depending on what is selected from the first DropdownButtonForm

I am developing a mobile application with Flutter. I am preparing a registration page for the application. On the registration page, I want to get the city and county where the user lives. I put two DropdownButtonForm of this.

After the user selects the city in the first DropdownButtonForm, the second DropdownButtonForm will have county options. I was able to do this with this code:

   List<DropdownMenuItem<String>> kahramanmarasDistricts = [
      const DropdownMenuItem(
        value: "Onikişubat",
        child: Text("Onikişubat"),
      ),
      const DropdownMenuItem(
        value: "Dulkadiroğlu",
        child: Text("Dulkadiroğlu"),
      ),
      const DropdownMenuItem(
        value: "Elbistan",
        child: Text("Elbistan"),
      ),
      const DropdownMenuItem(
        value: "Afşin",
        child: Text("Afşin"),
      ),
      const DropdownMenuItem(
        value: "Türkoğlu",
        child: Text("Türkoğlu"),
      ),
      const DropdownMenuItem(
        value: "Pazarcık",
        child: Text("Pazarcık"),
      ),
      const DropdownMenuItem(
        value: "Göksun",
        child: Text("Göksun"),
      ),
      const DropdownMenuItem(
        value: "Andırın",
        child: Text("Andırın"),
      ),
      const DropdownMenuItem(
        value: "Çağlayancerit",
        child: Text("Çağlayancerit"),
      ),
      const DropdownMenuItem(
        value: "Nurhak",
        child: Text("Nurhak"),
      ),
      const DropdownMenuItem(
        value: "Ekinözü",
        child: Text("Ekinözü"),
      ),
    ];
    
    List<DropdownMenuItem<String>> diyarbakirDistricts = [
      const DropdownMenuItem(
        value: "Bağlar",
        child: Text("Bağlar"),
      ),
      const DropdownMenuItem(
        value: "Bismil",
        child: Text("Bismil"),
      ),
      const DropdownMenuItem(
        value: "Çermik",
        child: Text("Çermik"),
      ),
      const DropdownMenuItem(
        value: "Çınar",
        child: Text("Çınar"),
      ),
      const DropdownMenuItem(
        value: "Çüngüş",
        child: Text("Çüngüş"),
      ),
      const DropdownMenuItem(
        value: "Dicle",
        child: Text("Dicle"),
      ),
      const DropdownMenuItem(
        value: "Egir",
        child: Text("Eğir"),
      ),
      const DropdownMenuItem(
        value: "Ergani",
        child: Text("Ergani"),
      ),
      const DropdownMenuItem(
        value: "Hani",
        child: Text("Hani"),
      ),
      const DropdownMenuItem(
        value: "Hazro",
        child: Text("Hazro"),
      ),
      const DropdownMenuItem(
        value: "Kayapınar",
        child: Text("Kayapınar"),
      ),
      const DropdownMenuItem(
        value: "Hocaköy",
        child: Text("Hocaköy"),
      ),
      const DropdownMenuItem(
        value: "Kulp",
        child: Text("Kulp"),
      ),
      const DropdownMenuItem(
        value: "Lice",
        child: Text("Lice"),
      ),
      const DropdownMenuItem(
        value: "Silvan",
        child: Text("Silvan"),
      ),
      const DropdownMenuItem(
        value: "Sur",
        child: Text("Sur"),
      ),
      const DropdownMenuItem(
        value: "Yenişehir",
        child: Text("Yenişehir"),
      ),
    ];
List<DropdownMenuItem<String>> citys = [
  const DropdownMenuItem(
    value: "Kahramanmaraş",
    child: Text("Kahramanmaraş"),
  ),
  const DropdownMenuItem(
    value: "Diyarbakır",
    child: Text("Diyarbakır"),
  ),
];
// ...
SelectCityDropDownField(),
SelectDistrictDropDownField(),

  Widget SelectCityDropDownField() {
    return Theme(
      data: Theme.of(context).copyWith(
        colorScheme: ThemeData().colorScheme.copyWith(
              primary: Colors.red,
            ),
      ),
      child: DropdownButtonFormField(
        decoration: InputDecoration(
          prefixIcon: const Icon(
            Icons.location_city,
            color: Color(0xFFCB3126),
          ),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(50),
          ),
          enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(50),
            borderSide: const BorderSide(
              color: Color(0xFFCB3126),
            ),
          ),
        ),
        items: citys
            .map(
              (e) => DropdownMenuItem<String>(
                value: e.value,
                child: e.child,
              ),
            )
            .toList(),
        onChanged: (value) {
          setState(() {
            selectedCity = value.toString();
          });
        },
      ),
    );
  }

  Widget SelectDistrictDropDownField() {
    return Theme(
      data: Theme.of(context).copyWith(
        colorScheme: ThemeData().colorScheme.copyWith(
              primary: Colors.red,
            ),
      ),
      child: DropdownButtonFormField(
        decoration: InputDecoration(
          prefixIcon: const Icon(
            Icons.location_city,
            color: Color(0xFFCB3126),
          ),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(50),
          ),
          enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(50),
            borderSide: const BorderSide(
              color: Color(0xFFCB3126),
            ),
          ),
        ),
        items: districtsItem(),
        onChanged: (value) {
          setState(() {
            selectedDistrict = value.toString();
          });
        },
      ),
    );
  }

  districtsItem() {
    switch (selectedCity) {
      case "Kahramanmaraş":
        return kahramanmarasDistricts;

      case "Diyarbakır":
        return diyarbakirDistricts;
    }
  }

I'm having a problem with something. The problem is this: For example, let's choose the province of Kahramanmaraş and choose Elbistan as the district. Then when I change the city to Diyarbakır, it gives an error. In other words, when I choose a different province after choosing the district, I get an error. This is error;

The following assertion was thrown building Builder(dirty, dependencies: [_FocusMarker]):
There should be exactly one item with [DropdownButtonFormField]'s value: Çermik. 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 939 pos 15: 'items == null || items.isEmpty || value == null ||
              items.where((DropdownMenuItem<T> item) {
                return item.value == value;
              }).length == 1'

How can I solve this problem? Thanks in advance for your help.

Upvotes: 2

Views: 44

Answers (1)

Jaecheol Park
Jaecheol Park

Reputation: 702

It is because your districts' lists conflict when rendering.

You have to set key property to distinguish them.

child: DropdownButtonFormField(
  key: selectedCity == 'Kahramanmaraş'
    ? const Key('Kahramanmaraş')
    : const Key('Diyarbakır'),
  ...

You could learn more about key from below youtube link.

https://www.youtube.com/watch?v=kn0EOS-ZiIc&t=1s

Upvotes: 1

Related Questions