Search code examples
flutterdartdrop-down-menudropdownbuttonflutter-futurebuilder

Flutter: There should be exactly one item with [DropdownButton]'s value


I am trying to create a dropdown button in Flutter. I am getting a List from my database then I pass the list to my dropdownButton everything works the data is shown as intended but when I choose an element from it I get this error:

There should be exactly one item with [DropdownButton]'s value: Instance of 'Tag'. 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 805 pos 15: 'items == null || items.isEmpty || value == null ||
          items.where((DropdownMenuItem<T> item) {
            return item.value == value;
          }).length == 1'

I tried setting DropdownButton value to null it works but then I can't see the chosen element.

Here is my code:

FutureBuilder<List<Tag>>(
    future: _tagDatabaseHelper.getTagList(),
    builder: (BuildContext context, AsyncSnapshot<List<Tag>> snapshot) {
      if (!snapshot.hasData) {
        return Center(
          child: CircularProgressIndicator(),
        );
      }
      return ListView(
        children: <Widget>[
          SizedBox(
            height: MediaQuery.of(context).size.height * 0.2,
          ),
          Container(
            margin: EdgeInsets.symmetric(
                horizontal: MediaQuery.of(context).size.width * 0.07),
            child: Theme(
              data: ThemeData(canvasColor: Color(0xFF525A71)),
              child: DropdownButton<Tag>(
                value: _selectedTag,
                isExpanded: true,
                icon: Icon(
                  Icons.arrow_drop_down,
                  size: 24,
                ),
                hint: Text(
                  "Select tags",
                  style: TextStyle(color: Color(0xFF9F9F9F)),
                ),
                onChanged: (value) {
                  setState(() {
                    _selectedTag = value;
                  });
                },
                items: snapshot.data.map((Tag tag) {
                  return DropdownMenuItem<Tag>(
                    value: tag,
                    child: Text(
                      tag.tagTitle,
                      style: TextStyle(color: Colors.white),
                    ),
                  );
                }).toList(),
                value: _selectedTag,
              ),
            ),
          ),

I used futureBuilder to get my List from database.


Solution

  • Well, since no problem has an exact same solution. I was facing the same issue with my code. Here is How I fixed this.

    CODE of my DropdownButton:

    DropdownButton(
       items: _salutations
             .map((String item) =>
                 DropdownMenuItem<String>(child: Text(item), value: item))
             .toList(),
        onChanged: (String value) {
           setState(() {
             print("previous ${this._salutation}");
             print("selected $value");
             this._salutation = value;
                });
              },
         value: _salutation,
    ),
    

    The Error

    In the code snippet below, I am setting the state for a selection value, which is of type String. Now problem with my code was the default initialization of this selection value. Initially, I was initializing the variable _salutation as:

    String _salutation = ""; //Notice the empty String.
    

    This was a mistake!

    Initial selection should not be null or empty as the error message correctly mentioned.

    'items == null || items.isEmpty || value == null ||

    And hence the crash:

    crash_message

    Solution
    Initialize the value object with some default value. Please note that the value should be the one of the values contained by your collection. If it is not, then expect a crash.

      String _salutation = "Mr."; //This is the selection value. It is also present in my array.
      final _salutations = ["Mr.", "Mrs.", "Master", "Mistress"];//This is the array for dropdown