Error in DropdownButton. There should be exactly one item with [DropdownButton]'s value,

Issue

I have created the DropdownBotton inside the ListView and i have a list of values which needs to be displayed in the DropdownMenuItem.

I have 2 questions with respect to DropdownBotton,

  1. How to set the default value in the DropdownButton for my scenario.
  2. (console error)
There should be exactly one item with [DropdownButton]'s value: $ 5.50 Pineapple Jack (S). 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 915 pos 15: 'items == null || items.isEmpty || value == null ||
              items.where((DropdownMenuItem<T> item) {
                return item.value == value;
              }).length == 1'

Below is my code:

ListView.builder(
  scrollDirection: Axis.vertical,
  shrinkWrap: true,
  physics: const ScrollPhysics(),
  itemCount: snapshot.data!.length,
  itemBuilder: (_, index) {

    List<String> selectedItemValue = <String>[
    ("\$${snapshot.data![index].price} ${snapshot.data![index].productType.type1}"),
    ("\$${snapshot.data![index].price} ${snapshot.data![index].productType.type2}"),
    ("\$${snapshot.data![index].price} ${snapshot.data![index].productType.type3}")];
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(
          margin: const EdgeInsets.symmetric(
              horizontal: 10, vertical: 5),
          padding: const EdgeInsets.all(5.0),
          child: DropdownButtonHideUnderline(
                child: DropdownButton<String>(
                  value: dropdownValue,
                  items: selectedItemValue.map((dropValue) {
                  return DropdownMenuItem<String>(
                              value: dropValue,
                              child: Text(dropValue),
                            );
                          }).toList(),
                          onChanged:
                              (newDropdownValue) {
                            setState(() {
                              dropdownValue =
                              newDropdownValue!;
                              print(
                                  'dropdown: $dropdownValue');
                            });
                          },
                        ),
                      ),
                ),
        ],
    );
  }
),

Please someone help me on this issue, Thanks in advance.

Solution

DropdownButton‘s value should be unique among DropdownMenuItem‘ values and There must be one DropDownMenuItem in items which exactly matches the current value of the DropDownButton.
in your case you are not setting DropdownButtons value from selectedItemValue. Therefore answers for your questions are,

  1. set initial value of the DropdownButton which you want’s to be your default value from selectedItemValue.

  2. to avoid the error, move your DropdownButton to separate StatefullWidget (CustomDropdownButton in this case.). change your code as follows.

ListView.builder(
  scrollDirection: Axis.vertical,
  shrinkWrap: true,
  physics: const ScrollPhysics(),
  itemCount: snapshot.data!.length,
  itemBuilder: (_, index) {

    List<String> selectedItemValue = <String>[
    ("\$${snapshot.data![index].price} ${snapshot.data![index].productType.type1}"),
    ("\$${snapshot.data![index].price} ${snapshot.data![index].productType.type2}"),
    ("\$${snapshot.data![index].price} ${snapshot.data![index].productType.type3}")];

final defaultValue = selectedItemValue[1];

        return CustomDropdownButton(defaultValue:defaultValue, values: selectedItemValue, onItemSelected: (value) {print("Selected Item : $value");});
      }
    ),

CustomDropdownButton class

class CustomDropdownMenu extends StatefulWidget {
  const CustomDropdownMenu(
      {Key? key,
      required this.defaultValue,
      required this.values,
      required this.onItemSelected})
      : super(key: key);
  final dynamic Function(String? selectedValue) onItemSelected;
  final String defaultValue;
  final List<String> values;
  @override
  _CustomDropdownMenuState createState() => _CustomDropdownMenuState();
}

class _CustomDropdownMenuState extends State<CustomDropdownMenu> {
  late String dropdownValue;

  @override
  void initState() {
    super.initState();
    dropdownValue = widget.defaultValue;
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Container(
          margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
          padding: const EdgeInsets.all(5.0),
          child: DropdownButtonHideUnderline(
            child: DropdownButton<String>(
              value: dropdownValue,
              items: widget.values.map((dropValue) {
                return DropdownMenuItem<String>(
                  value: dropValue,
                  child: Text(dropValue),
                );
              }).toList(),
              onChanged: (newDropdownValue) {
                setState(() {
                  dropdownValue = newDropdownValue!;
                });
                widget.onItemSelected(newDropdownValue);
              },
            ),
          ),
        ),
      ],
    );
  }
}

Answered By – Lakmal Fernando

Answer Checked By – Pedro (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *