Home > front end >  How to get DropdownMenuItem from a list
How to get DropdownMenuItem from a list

Time:10-18

I have tried to use a function and for in loop to loop through a list and then create dropdownMenuItems. I am getting this 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'. I have look through similar solutions stating that the default value should be one of the values of the list which is not my case Below is the list

const List<String> currenciesList = [
  'AUD',
  'BRL',
  'CAD',
  'CNY',
  'EUR',
  'GBP',
  'HKD',
  'IDR',
  'ILS',
  'INR',
  'JPY',
  'MXN',
  'NOK',
  'NZD',
  'PLN',
  'RON',
  'RUB',
  'SEK',
  'SGD',
  'USD',
  'ZAR'
];

and the loop

String selectedCurrency = 'USD';
  List<DropdownMenuItem<String>> dropdownItems = [];
  List<DropdownMenuItem<String>> getDropDownItems() {
    for (String currency in currenciesList) {
      var newItem = DropdownMenuItem(
        child: Text(currency),
        value: currency,
      );
      dropdownItems.add(newItem);
    }
    return dropdownItems;
  }

lastly the dropdownbutton

child: DropdownButton<String>(
              value: selectedCurrency,
              items: getDropDownItems(),
              onChanged: (value) {
                setState(() {
                  selectedCurrency = value!;
                });
              },

Please help me understand what i must have done wrong

CodePudding user response:

Your code-snippet

 DropdownButton<String>(
              value: selectedCurrency,
              items: getDropDownItems(), ///<= adding items on every state-build  
              onChanged: (value) {
                setState(() {
                  selectedCurrency = value!;
                });
              },

On state changes means after you click on DropdownMenuItem you are calling again getDropDownItems(), in this case our it will add DropdownMenuItem again to dropdownItems, and so the DropdownButton having duplicate values, and you are getting errors.

Use initState to call it once, or just initialize the dropdownMenuItem.

Here is the Solution Widget


class _ItemSectionState extends State<ItemSection> {
  List<DropdownMenuItem<String>> dropdownItems = []; //* you can make nullable if you want, I'm doing it to force having String. 

  String selectedCurrency = 'USD';

  @override
  void initState() {
    super.initState();

    dropdownItems = List.generate(
      currenciesList.length,
      (index) => DropdownMenuItem(
        value: currenciesList[index],
        child: Text(
          currenciesList[index],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          DropdownButton<String>(
            items: dropdownItems,
            value: selectedCurrency,
            onChanged: (value) {
              setState(() {
                selectedCurrency = value!;
              });
            },
          ),
        ],
      ),
    );
  }
}

CodePudding user response:

The error occurs due to duplicate values..

When you try to change the value of the drop down, the getDropDownItems function is rerun and the logic in there just duplicates the values for the dropdown.

a quick fix would be to simply map over the currenciesList as opposed to writing a function to add the widgets to a List as shown below:


  String selectedCurrency = 'USD';

...

child: DropdownButton<String>(
        value: selectedCurrency,
        items: currenciesList.map((currency) => DropdownMenuItem(
          child: Text(currency),
          value: currency,
         ),
        ),
       onChanged: (value) {
         setState(() {
           selectedCurrency = value!;
         });
         },

...

  • Related