9
votes

I' m gettings items from JSON and displaying them in a dropdown. When the person select an item from the dropdown list, I get the selection but the selected item doesn't change.

For example we have (tokyo, paris, new york) in the list. By default selection is tokyo. When the person select paris, I get it but the selection doesn't change in the dropdown.

Here is my code:

new DropdownButton(
  value: cities.elementAt(0),
  hint: new Text("Ville"),
  items: cities.map((String value) {
    return new DropdownMenuItem(
      value: value,
      child: new Row(
        children: <Widget>[
          new Icon(
            Icons.location_city,
            color: Colors.deepOrange,
          ),
          new Text(value)
        ],
      ),
    );
  }).toList(),
  onChanged: (String value) {
    getTravelCity(value);
  },
),

When the person select an item, it still showing the default value.

9
i tried it but still have the same problemPondikpa Tchabao

9 Answers

18
votes

make sure you are not declaring the selectedValue inside the Widget the below example works for me perfectly.

enter image description here

here is the working code on dartpad to test it out

var currentSelectedValue;
const deviceTypes = ["Mac", "Windows", "Mobile"];

 Widget typeFieldWidget() {
return Container(
  padding: EdgeInsets.symmetric(horizontal: 20),
  child: FormField<String>(
    builder: (FormFieldState<String> state) {
      return InputDecorator(
        decoration: InputDecoration(
            border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(5.0))),
        child: DropdownButtonHideUnderline(
          child: DropdownButton<String>(
            hint: Text("Select Device"),
            value: currentSelectedValue,
            isDense: true,
            onChanged: (newValue) {
              setState(() {
                currentSelectedValue = newValue;
              });
              print(currentSelectedValue);
            },
            items: deviceTypes.map((String value) {
              return DropdownMenuItem<String>(
                value: value,
                child: Text(value),
              );
            }).toList(),
          ),
        ),
      );
    },
  ),
);
}
7
votes
This is the solution: "StatefulBuilder()"

       Future<void> AgregarContacto() async {
             String dropdownValue = 'Exento';
             return showDialog<void>(
           context: context,
           barrierDismissible: true, // user must tap button!
           builder: (BuildContext context) {
                 return StatefulBuilder(
                   builder: (BuildContext context, StateSetter setState) {
                   return AlertDialog(
                   title: Text('Agregar cliente', textAlign: TextAlign.center,),
                   content:
                     SingleChildScrollView(
                       child: ListBody(
                         children: <Widget>[
                           Center(
                             child: Material(
                               type: MaterialType.transparency,
                               child: DropdownButton<String>(
                                 items: <String>[
                                   'Responsable inscripto',
                                   'Monotributista',
                                   'Exento',
                                   'Consumidor final',
                                   'No responsable'
                                 ]
                                     .map<DropdownMenuItem<String>>((
                                     String value) {
                                   return DropdownMenuItem<String>(
                                     value: value,
                                     child: Text(value),
                                   ); //DropMenuItem
                                 }).toList(),
                                 value: dropdownValue,
                                 onChanged: (String newValue) {
                                   setState(() {
                                     dropdownValue = newValue;
                                     print("new${newValue}");
                                   }); //setState
                                 },
                                 //OnChange
                                 isExpanded: false,
                                 hint: Text('Responsable inscripto',
                                   style: TextStyle(color: Colors.black),),
                               ),
                             ), //Material
                           ), //Center
                         ],
                       ),
                     ),
                   actions: <Widget>[
                         FlatButton(
                           child: Text('Regret'),
                           onPressed: () {
                             Navigator.of(context).pop();
                          },
                       ),
                    ],
                 );
            }
            );
           },
         );
       }
2
votes

this was a bug reported in the Github of Flutter.

The correct implementions is:

class _DropdownButtonBugState extends State<DropdownButtonBug> {

  final List<String> _items = ['One', 'Two', 'Three', 'Four'].toList();

  String _selection;

  @override
  void initState() {
    _selection = _items.first;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final dropdownMenuOptions = _items
      .map((String item) =>
        new DropdownMenuItem<String>(value: item, child: new Text(item))
      )
      .toList();

    return new Scaffold(
      body: new DropdownButton<String>(
        value: _selection,
        items: dropdownMenuOptions,
        onChanged: (s) {
          setState(() {
            _selection = s;
          });
        }
      )
    );
  }
}
1
votes

For those who are facing this problem in future. Use variable to set the value to DropdownButton and when the onChanged called update the variable using setState

Expanded(child: DropdownButton<String>(
          items: cities.map((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value),
            );
          }).toList(),
          value: city,
          onChanged: (String val) {
            _onDropDownChanged(val);
          },
        ),)

update the city variable by using state

void _onDropDownChanged(String val) {
    setState(() {
      this.city = val;
    });
  }

For further information check the link below

https://github.com/FazalHussain/Flutter-Demo/blob/trip_cost_app/lib/main.dart

1
votes

The Dropdown Button can be wrapped inside a StatefulBuilder() widget if the selected values are not updated after the selction.

0
votes

Because you need to update the "value: " parameter with "setState(() {});" method and the new value must be of the same type of the one passed to "onChanged:". I suggest tho do this because your are able to change dynamically your icon.

1) declare a new class in the top of the file;

class city {
  final String name;
  final IconData icon;

  const city({
    this.name,
    this.icon,
  });
}

2) the add this in the state of your widget:

class yourState extend<myWidget>{

List<city> cities = [
    new city(name: "tokio", icon: Icons.location_city),
    new city(name: "paris", icon: Icons.location_city),
    new city(name: "new york", icon: Icons.location_city),
  ];

int index = 0;

Widget drop() {
    return DropdownButton(
        value: cities[index],
        hint: new Text("Ville"),
        items: cities.map((city value) {
          return new DropdownMenuItem(
            value: value,
            child: new Row(
              children: <Widget>[
                new Icon(
                  value.icon,
                  color: Colors.deepOrange,
                ),
                new Text(value.name)
              ],
            ),
          );
        }).toList(),
        onChanged: (city value) {
          setState(() {
            index = cities.indexOf(value);
            print(index);
          });
          //getTravelCity(value.name);
        });
  }

}

now call "drop()" where you want your DropDown. Bye!!

0
votes

Is used this code in my most recent app and it works. Maybe you could compare it to your code.

return DropdownButton<String>(
    style: Theme.of(context).textTheme.title,
    items: _persons.map((String val) {
      return new DropdownMenuItem<String>(
        value: val,
        child: new Container(
          child: new Card(
            child: new Row(children: <Widget>[
              new Icon(Icons.person),
              new Text(val),
            ]),
          ),
        ),
      );
    }).toList(),
    hint: new Card(
        child: new Row(children: <Widget>[
      new Icon(Icons.person),
      new Text("check"),
    ])),
    value: _selectedPerson,
    onChanged: (newVal) {
      _selectedPerson = newVal;
      setState(() {});
    });
0
votes

You hard-coded the first city as value for the dropdown.

new DropdownButton(
            value: cities.elementAt(0), //this one
...

You need to have some state variable to hold the selected city.

class YourStatefulWidgetState extends State<YourStatefulWidget> {
  @override
  initState() {
   super.initState();
   selectedCity = cities.elementAt(0)
  }

 @override
 Widget build(BuildContext context) {
   ...
   new DropdownButton(
            value: selectedCity,
            hint: new Text("Ville"),
            items: cities.map((String value) {
              return new DropdownMenuItem(value: value,
                child: new Row(
                  children: <Widget>[
                    new Icon(
                      Icons.location_city, color: Colors.deepOrange,),
                    new Text(value)
                  ],
                ),);
            }).toList(),
            onChanged: (String value) {
              setState(() {
                selectedCity = getTravelCity(value);
              });
            },),
     ...
-1
votes

I tired all the options, including all the flutter issues. But after 2 hours of search. I found my solution for my Bloc implemented widget.

 onChanged: (Object value) {
     selectedCity = getTravelCity(value);
     setState((){}; });
        );

You can feel the difference here. Since I'm populating the list under BlocBuilder with some state, It won't allow you to rebuild the dropdown menu. So after setting the dropdownValue then call the setState method. It will allow you to reflect the value.

Thanks!