25

I have written a pretty extensive form using DropdownButton and TextField widgets. The concept is that I have a StatefulWidget, where the class of State<StatefulWidget> contains 2 methods that return the widget I want to build. This way I can easily access and use the entered data and pass it along a function to compose an e-mail out of them.

However, when I select an item from the options, the framework throws an exception during the rebuild. I put in some log functions, and it shows that the setState() method successfully saves the value to selectedValue variable.

Widget buildMultiChoiceInputRow(var label, List<String> values) {
    final List<String> options = values.toList();
    selection = options.first;

    final dropDownMenuOptions = options.map((String value) {
      return new DropdownMenuItem<String>(
        value: value,
        child: new Text(value),
      );
    }).toList();

    return new Column(
      children: <Widget>[
        new Row(
          children: <Widget>[
            new Expanded(
              child: new Container(
                  padding:
                      const EdgeInsets.only(left: 5.0, top: 2.0, right: 5.0),
                  child: new Text(label, style: commonInfoCardInfoTextBlack16Bold)),
            ),
          ],
        ),
        new Row(
          children: <Widget>[
            new Expanded(
              child: new Container(
                padding: const EdgeInsets.only(left: 5.0, right: 5.0),
                child: new DropdownButton(
                value: selectedValue,
                items: dropDownMenuOptions,
                onChanged: (selection) {
                  setState(() {
                    selectedValue = selection;
                    switch (label) {
                      case labelVirtualAdoption:
                        tempAdoptionType =
                            composeMultiChoiceAnswer(label, selection);
                            print(selection);
                            print(selectedValue);
                        break;
                          case labelAskedAboutSpecies:
                            tempAskedAboutSpecies =
                                composeMultiChoiceAnswer(label, selection);
                            break;
                          case labelHouseOrFlat:
                            tempHouseOrFlat =
                                composeMultiChoiceAnswer(label, selection);
                            break;
                            ....
                          default:
                            break;
                        }
                      });
                    }),
              ),
            )
          ],
        ),
        new Divider(color: Colors.transparent)
      ],
    );
  }

Here is the exception:

I/flutter (20998): The following assertion was thrown building AdoptionInput(dirty, state: AdoptionInputState#3cc80):
I/flutter (20998): 'package:flutter/src/material/dropdown.dart': Failed assertion: line 481 pos 15: 'value == null ||
I/flutter (20998): items.where((DropdownMenuItem<T> item) => item.value == value).length == 1': is not true.

And here is the stack, showing that the exception is thrown during the rebuild:

I/flutter (20998): #2      new DropdownButton (package:flutter/src/material/dropdown.dart)
I/flutter (20998): #3      AdoptionInputState.buildMultiChoiceInputRow (package:osszefogasaszanhuzokert/adoptionPageUtilities.dart:443:28)
I/flutter (20998): #4      AdoptionInputState.build (package:osszefogasaszanhuzokert/adoptionPageUtilities.dart:639:11)
I/flutter (20998): #5      StatefulElement.build (package:flutter/src/widgets/framework.dart:3730:27)
I/flutter (20998): #6      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3642:15)
I/flutter (20998): #7      Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
I/flutter (20998): #8      BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2242:33)

The problem seems really similar to a former bug in flutter, but if I try to initialize the selection and selectedValue in initState(), the same exception will be thrown right as the form is built for the first time.

What am I missing here?

1
  • In the meantime, I found that the exception is thrown when a widget is built that has different values that "igen" "nem" (or I think different from the first one I used) Commented May 18, 2018 at 5:57

7 Answers 7

54

Your "value" for DropdownButton should be set to 'null' or or be one from the values list.

DropdownButton(
      value: null,
      isDense: true,
      onChanged: (String newValue) {
        // somehow set here selected 'value' above whith 
       // newValue
       // via setState or reactive.
      },
      items: ['yellow', 'brown', 'silver'].map((String value) {
        return DropdownMenuItem(
          value: value,
          child: Text(value),
        );
      }).toList(),
    ),

So for my example DropdownButton value should be set to null or be 'yellow' or 'brown' or 'silver'.

Sign up to request clarification or add additional context in comments.

2 Comments

But after make select: null, the selected value is not showing into the dropdown
yes selected value not shown? is there any solution to fix this issue
14

Extending above answer with the second case where I was stuck.

Your "value" for DropdownButton should be set to 'null' or be one from the values list.

Your 'values' should also be different in every item value.

for example: Avoid this

 items.add(DropdownMenuItem(
  value: 1.toString(),
  child: Text(1.toString()),
));
items.add(DropdownMenuItem(
  value: 1.toString(),
  child: Text(1.toString()),
));

Avoid repeating the values.

Comments

0

A bit off time, but, the code worked when I passed null as the "value" but I was having this problem when I placed a value that was included on the "Items". The problem was that the "Items" had a duplicate value, so it seems that you should provide all different items in the list passed to the "Items".

Comments

0

here is the right way:

 import 'package:flutter/material.dart';

class RegisterFragments extends StatefulWidget {
  RegisterFragments({Key key, this.step}) : super(key: key);
  final int step;

  _RegisterFragmentsState createState() => _RegisterFragmentsState();
}

class _RegisterFragmentsState extends State<RegisterFragments> {
  Map<String, bool> values = {"abc": false, "def": true, "ghi": false};
  List<String> _do = ['One', 'Two', 'Free', 'Four'];
  String _dropdownValue = 'One';

  @override
  Widget build(BuildContext context) {
    switch (widget.step) {
      case 0:
        return buildDo();
        break;
      case 1:
        return Container(
          child: ListView.builder(
            shrinkWrap: true,
            itemCount: values.length,
            itemBuilder: (BuildContext context, int index) {
              switch (widget.step) {
                case 0:
                  return buildDo();
                  break;
                case 1:
                  return buildService(context, index);
                  break;
                default:
                  return Container();
                  break;
              }
            },
          ),
        );
        break;
      default:
        return Container();
        break;
    }
  }

  Widget buildService(BuildContext context, int index) {
    String _key = values.keys.elementAt(index);

    return Container(
      child: Card(
        child: CheckboxListTile(
          title: Text(_key),
          onChanged: (bool value) {
            setState(() {
              values[_key] = value;
            });
          },
          value: values[_key],
        ),
      ),
    );
  }

  Widget buildDo() {
    return DropdownButton<String>(
      isExpanded: true,
      hint: Text("Service"),
      items: _do.map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value),
        );
      }).toList(),
      onChanged: (String newValue) {
        setState(() {
          this._dropdownValue = newValue;
        });
      },
      value: _dropdownValue,
    );
  }
}

list and dorpdown value

   List<String> _do = ['One', 'Two', 'Free', 'Four'];
   String _dropdownValue = 'One';

dropdown items

tems: _do.map<DropdownMenuItem<String>>((String value) {   
  return DropdownMenuItem<String>( ** 
     value: value,
          child: Text(value),
        );
      }).toList(),
      onChanged: (String newValue) {
        setState(() {
          this._dropdownValue = newValue;
        });
      },
      value: _dropdownValue,

1 Comment

Please add comments and highlight the parts that you did differently than poster.
0

Use var to declare variable instead of String. Now you don't need to set the default value to null.

var dropdownvalue;

DropdownButton<String>(
                    value: dropdownvalue,
                    icon: Icon(Icons.keyboard_arrow_down),
                    iconSize: 28,
                    elevation: 20,
                    onChanged: (String newval){
                      setState((){
                        dropdownvalue = newval;
                      });

                    },
                    items: <String>["Registration","Verification", "ArenaRun"]
                        .map<DropdownMenuItem<String>>((String value){
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(value),
                        );
                    }).toList(),
                  ),

Comments

0

I was doing a value.toString() and the null was being converted to "null"!

Comments

0

Although this question was asked four years ago and the Flutter SDK may have changed since then, if someone comes across this issue, one solution is to remove duplicate values in the DropdownMenuItem. Alternatively, you can add key: ValueKey(item) in your DropdownMenuItem widget. For instance, your DropdownButton code should look like this:

DropdownButton(
     value: selectedValue,
     items: dropDownMenuOptions,
     key: ValueKey(selectedValue),
)

Also make sure that the initial value assigned to "value:" for selectedValue is present in the list passed to "items:".

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.