skip to Main Content

Hi I’m new to Flutter.

I had been getting an exception There should be exactly one item with [DropdownButton]'s value: . when using DropdownButton class. And it was resolved once by setting an initial select referring to this Q&A.

But I don’t want to set an initial value. Is there any way not to set it but no exception?

Thanks,

P.S.
I have two classes and one constant to show the dropdown button. Here is the constant that is a list for creating DropdownMenuItems:

List<String> prefectures = const [
  '北海道',
  '青森県',
  '岩手県',
  '宮城県',
  '秋田県',
  '山形県',
  '福島県',
  '茨城県',
  '栃木県',
  '群馬県',
...

And this is the class that expand DropdownButton.

class MyDropdownButton extends StatelessWidget {
  final String                 value;
  final void Function(String?) onChanged;
  final List<String>           options;
  final String?                hintText;
  const MyDropdownButton(
    {required this.value, required this.onChanged, required this.options, this.hintText, super.key}
  );

  List<DropdownMenuItem<String>> createOptions() {
    return options.toSet().map<DropdownMenuItem<String>>(
      (option) => DropdownMenuItem(value : option, child : Text(option))
    ).toList();
  }

  @override
  Widget build(BuildContext context) {
    return DropdownButtonHideUnderline(
      child : DropdownButton(
        elevation : 3,
        items     : createOptions(),
        onChanged : onChanged,
        style     : const TextStyle(
          color    : Colors.black,
          fontSize : 15
       ),
        value     : value
      )
    );
  }
}

And this is where I use the class above:

MyDropdownButton(
  // They are also passed from other class.
  value     : widget.prefectureValue,     // this has null value
  onChanged : widget.onChangedPrefecture, // (String? newValue) => setState(() => _prefectureValue = newValue);
  options   : prefectures
)

2

Answers


  1. The solution is simple keep the initialValue null provided that you are on the latest version of flutter 3.5 or above

    var _selectedItem;
      Widget buildDropdownButton() {
        return DropdownButton(
          hint: const Text('Select Item'),
          value: _selectedItem,
          onChanged: (value) {
            setState(() {
              _selectedItem = value;
            });
          },
          items: ["Item 1", "Item 2", "Item 3", "Item 4"]
              .map((e) => DropdownMenuItem(
                    value: e,
                    child: Text(e),
                  ))
              .toList(),
        );
      }
    

    the output will look like the following
    enter image description here

    Login or Signup to reply.
  2. There should be exactly one item with [DropdownButton]’s value: means you are having same value more than one DropdownMenuItem. You can convert the data-list to Set, most time it works.

    Here the items is

     List<String> items = [...];
     String? selectedItem;
    

    And the dropDownButton

    DropdownButton<String?>(
      items: items
          .toSet()
          .map(
            (e) => DropdownMenuItem<String?>(
              value: e,
              child: Text(e),
            ),
          )
          .toList(),
      onChanged: (value) {},
    )
    

    Fixed model

    class MyDropdownButton extends StatelessWidget {
      final String? value;
      final void Function(String?) onChanged;
      final List<String> options;
      final String? hintText;
      const MyDropdownButton(
          {required this.value,
          required this.onChanged,
          required this.options,
          this.hintText,
          super.key});
    
      List<DropdownMenuItem<String>> createOptions() {
        return options
            .toSet()
            .map<DropdownMenuItem<String>>(
                (option) => DropdownMenuItem(value: option, child: Text(option)))
            .toList();
      }
    
      @override
      Widget build(BuildContext context) {
        return DropdownButtonHideUnderline(
            child: DropdownButton(
                elevation: 3,
                items: createOptions(),
                onChanged: onChanged,
                style: const TextStyle(
                  color: Colors.black,
                  fontSize: 15,
                ),
                value: value));
      }
    }
    

    Here is how I am using it

    List<String> prefectures = const [
        '北海道',
        '青森県',
        '岩手県',
        '宮城県',
        '秋田県',
        '山形県',
        '福島県',
        '茨城県',
        '栃木県',
        '群馬県',
      ];
    
      late String? value = prefectures.first;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            children: [
              MyDropdownButton(
                value: value, //null,
                onChanged: (v) {
                  setState(() {
                    value = v;
                  });
                }, 
                options: prefectures,
              ),
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search