Search code examples
flutterlistdropdownbutton

there should be exactly one item with dropdownbutton 's value either zero or 2 or more [DropdownMenuItem]s were detected with the same value


I'm newbie with flutter, can someone help me ? when I choose first dropdown, and choose the second dropdown, and then choose again the first dropdown, i get freeze error, I'm already set the variable list empty, but still not working, i get error :

there should be exactly one item with dropdownbutton 's value either zero or 2 or more [DropdownMenuItem]s were detected with the same value

this my code :

main.dart

 import 'package:flutter/material.dart';
    import 'package:perhitungan_pkt_kgb/data.dart';
    
    class HitungPkt extends StatefulWidget {
      const HitungPkt({super.key});
    
      @override
      State<HitungPkt> createState() => _HitungPktState();
    }
    
    class _HitungPktState extends State<HitungPkt> {
      @override
      Widget build(BuildContext context) {
        return Form(
          child: Column(
            children: [
              _buildDropdown(
                  label: 'Gol',
                  items: Data.gol.cast<Map<String, dynamic>>(),
                  onChanged: (String? newValue) {
                    setState(() {
                      // value dropdown nya kita masukan ke sebuah variabel
                      Data.golValue = newValue;
                      Data.vehicle?.clear();
                      Data.vehicle = Data.cekgol();
                    });
                  }),
    
              if (Data.vehicle != null)
                _buildDropdown(
                    label: 'Vechile',
                    items: Data.vehicle!.cast<Map<String, dynamic>>(),
                    onChanged: (String? newValue) {
                      setState(() {
                        // value dropdown nya kita masukan ke sebuah variabel
                        Data.vehicleValue = newValue;
                      });
                    }),
       ],
          ),
        );
      }
    
      Widget _buildDropdown({
        required String label,
        required List<Map<String, dynamic>> items,
        required void Function(String?) onChanged,
        String? value,
      }) {
        return DropdownButtonFormField<String>(
            decoration: InputDecoration(
              labelText: label,
              hintStyle: const TextStyle(color: Colors.blue),
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(10),
                borderSide: const BorderSide(color: Colors.blue),
              ),
              focusedBorder: OutlineInputBorder(
                borderSide: const BorderSide(color: Colors.blue),
                borderRadius: BorderRadius.circular(10),
              ),
              enabledBorder: OutlineInputBorder(
                borderSide: const BorderSide(color: Colors.blue),
                borderRadius: BorderRadius.circular(10),
              ),
              errorBorder: OutlineInputBorder(
                borderSide: const BorderSide(color: Colors.blue),
                borderRadius: BorderRadius.circular(10),
              ),
            ),
            value: value,
            items: items.map((item) {
              return DropdownMenuItem<String>(
                value: item['value'] as String,
                child: Text(item['label'] as String),
              );
            }).toList(),
            onChanged: onChanged);
      }
    }

data.dart

class Data{
static const List gol = [
    {'value': 'Car', 'label': 'Car'},
    {'value': 'Bus', 'label': 'Bus'},
    {'value': 'Plane', 'label': 'Plane'}
  ];
  static String? golValue;
  static String? vehicleValue;
  static List? vehicle;
  static List cekgol() {
    if (golValue == 'Car') {
      return [
        {'value': 'car1', 'label': 'car1'},
        {'value': 'car2', 'label': 'car2'},
        {'value': 'car3', 'label': 'car3'},
        {'value': 'car4', 'label': 'car4'},
        {'value': 'car5', 'label': 'car5'}
      ];
    } else if (golValue == 'Bus') {
      return [
        {'value': 'Bus1', 'label': 'Bus1'},
        {'value': 'Bus2', 'label': 'Bus2'},
        {'value': 'Bus3', 'label': 'Bus3'},
        {'value': 'Bus4', 'label': 'Bus4'}
      ];
    } else if (golValue == 'Plane') {
      return [
        {'value': 'Plane1', 'label': 'Plane1'},
        {'value': 'Plane2', 'label': 'Plane2'},
        {'value': 'Plane3', 'label': 'Plane3'},
        {'value': 'Plane4', 'label': 'Plane4'},
        {'value': 'Plane5', 'label': 'Plane5'}
      ];
    } else {
      return [];
    }
  }
}

Solution

  • The issue arises because you're likely setting the value of your DropdownButtonFormField to a value that isn't present in the items list you provide. When you change the first dropdown (Gol), you correctly clear the vehicle list, but you're not resetting the vehicleValue. This means the second dropdown tries to render with a vehicleValue that no longer exists in the newly populated vehicle list, causing the error.

    
    class Data {
      static const List gol = [
        {'value': 'Car', 'label': 'Car'},
        {'value': 'Bus', 'label': 'Bus'},
        {'value': 'Plane', 'label': 'Plane'}
      ];
      static String? golValue;
      static String? vehicleValue;
      static List? vehicle;
    
      static List cekgol() {
        if (golValue == 'Car') {
          return [
            {'value': 'car1', 'label': 'car1'},
            {'value': 'car2', 'label': 'car2'},
            {'value': 'car3', 'label': 'car3'},
            {'value': 'car4', 'label': 'car4'},
            {'value': 'car5', 'label': 'car5'}
          ];
        } else if (golValue == 'Bus') {
          return [
            {'value': 'Bus1', 'label': 'Bus1'},
            {'value': 'Bus2', 'label': 'Bus2'},
            {'value': 'Bus3', 'label': 'Bus3'},
            {'value': 'Bus4', 'label': 'Bus4'}
          ];
        } else if (golValue == 'Plane') {
          return [
            {'value': 'Plane1', 'label': 'Plane1'},
            {'value': 'Plane2', 'label': 'Plane2'},
            {'value': 'Plane3', 'label': 'Plane3'},
            {'value': 'Plane4', 'label': 'Plane4'},
            {'value': 'Plane5', 'label': 'Plane5'}
          ];
        } else {
          return [];
        }
      }
    }
    
    class HitungPkt extends StatefulWidget {
      const HitungPkt({super.key});
    
      @override
      State<HitungPkt> createState() => _HitungPktState();
    }
    
    class _HitungPktState extends State<HitungPkt> {
      @override
      Widget build(BuildContext context) {
        return Form(
          child: Column(
            children: [
              _buildDropdown(
                label: 'Gol',
                items: Data.gol.cast<Map<String, dynamic>>(),
                onChanged: (String? newValue) {
                  setState(() {
                    Data.golValue = newValue;
                    Data.vehicle?.clear();
                    Data.vehicle = Data.cekgol();
                    Data.vehicleValue = null; // Reset vehicleValue here!
                  });
                },
              ),
              if (Data.vehicle != null)
                _buildDropdown(
                  label: 'Vechile',
                  items: Data.vehicle!.cast<Map<String, dynamic>>(),
                  onChanged: (String? newValue) {
                    setState(() {
                      Data.vehicleValue = newValue;
                    });
                  },
                ),
            ],
          ),
        );
      }
    
      Widget _buildDropdown({
        required String label,
        required List<Map<String, dynamic>> items,
        required void Function(String?) onChanged,
      }) {
        return DropdownButtonFormField<String>(
          decoration: InputDecoration(
            labelText: label,
            hintStyle: const TextStyle(color: Colors.blue),
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(10),
              borderSide: const BorderSide(color: Colors.blue),
            ),
            focusedBorder: OutlineInputBorder(
              borderSide: const BorderSide(color: Colors.blue),
              borderRadius: BorderRadius.circular(10),
            ),
            enabledBorder: OutlineInputBorder(
              borderSide: const BorderSide(color: Colors.blue),
              borderRadius: BorderRadius.circular(10),
            ),
            errorBorder: OutlineInputBorder(
              borderSide: const BorderSide(color: Colors.blue),
              borderRadius: BorderRadius.circular(10),
            ),
          ),
          value: (label == "Gol")
              ? Data.golValue
              : Data.vehicleValue, // Use ternary for value
          items: items.map((item) {
            return DropdownMenuItem<String>(
              value: item['value'] as String,
              child: Text(item['label'] as String),
            );
          }).toList(),
          onChanged: onChanged,
        );
      }
    }