Flutter - DropdownButtonFormField value not updating

19,140

Solution 1

You need to create a new StatefulWidget class that should return your AlertDialog

class MyDialog extends StatefulWidget {
  @override
  _MyDialogState createState() => _MyDialogState();
}

class _MyDialogState extends State<MyDialog> {
  int _ratingController;

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          TextField(
            controller: _eateryController,
            autofocus: true,
            decoration:
            InputDecoration(labelText: 'Eatery', hintText: 'eg Pizza Hut'),
          ),
          TextField(
            controller: _supplierController,
            decoration: InputDecoration(
                labelText: 'Supplier', hintText: 'eg Deliveroo'),
          ),
          TextField(
            controller: _descriptionController,
            decoration: InputDecoration(
                labelText: 'Description', hintText: 'eg cheese pizza'),
          ),
          DropdownButtonFormField<int>(
            value: _ratingController,
            items: [1, 2, 3, 4, 5]
                .map((label) => DropdownMenuItem(
              child: Text(label.toString()),
              value: label,
            ))
                .toList(),
            hint: Text('Rating'),
            onChanged: (value) {
              setState(() {
                _ratingController = value;
              });
            },
          ),
        ],
      ),
      actions: <Widget>[
        FlatButton(
          onPressed: () {
            _handleSubmit(_eateryController.text, _supplierController.text,
                _descriptionController.text, _ratingController);
            Navigator.pop(context);
          },
          child: Text('Save'),
        ),
        FlatButton(
          onPressed: () => Navigator.pop(context),
          child: Text('Cancel'),
        )
      ],
    );
  }
}

Use it like this

showDialog(
  context: context,
  builder: (context) {
    return MyDialog();
  },
);

Solution 2

You can use statefulBuilder inside alert dialog.

return AlertDialog(
                                      title: new Text('Table'),
                                      content: StatefulBuilder(builder:
                                          (BuildContext context,
                                              StateSetter setState) {
                                        return Container(
                                          child: new SingleChildScrollView(
                                            scrollDirection: Axis.vertical,
                                            child: new Column(
                                              children: <Widget>[
                                                DropdownButtonFormField<String>(
                                                  value: dropdownValue,
                                                  style: TextStyle(
                                                      color: Colors.black87),
                                                  items: <String>[
                                                    'Lot 1',
                                                    'Lot 2',
                                                    'Lot 3',
                                                    'Lot 4',
                                                  ].map<
                                                          DropdownMenuItem<
                                                              String>>(
                                                      (String value) {
                                                    return DropdownMenuItem<
                                                        String>(
                                                      value: value,
                                                      child: Text(value),
                                                    );
                                                  }).toList(),
                                                  onChanged: (String newValue) {
                                                    setState(() {
                                                      dropdownValue = newValue;
                                                    });
                                                  },
                                                ),
```


Solution 3

It looks like you're calling setState in a wrong widget. The AlertDialog doesn't belong to ItemList's tree because it's located inside another Route. So calling setState inside _ItemListState won't rebuild the AlertDialog.

Consider pulling out content of AlertDialog into a separate StatefulWidget and putting int _ratingController into it's state.

Share:
19,140

Related videos on Youtube

L-R
Author by

L-R

Updated on September 15, 2022

Comments

  • L-R
    L-R over 1 year

    My Dropdown button value doesn't update until the AlertDialog box is closed and reopened.

    I have the variable set at the top of my class

    class _ItemListState extends State<ItemList> {
      int _ratingController;
    ...
    
    }
    

    Within the class I have an AlertDialog that opens a form, within here I have the DropdownButtonFormField

    
    AlertDialog(
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              TextField(
                controller: _eateryController,
                autofocus: true,
                decoration:
                    InputDecoration(labelText: 'Eatery', hintText: 'eg Pizza Hut'),
              ),
              TextField(
                controller: _supplierController,
                decoration: InputDecoration(
                    labelText: 'Supplier', hintText: 'eg Deliveroo'),
              ),
              TextField(
                controller: _descriptionController,
                decoration: InputDecoration(
                    labelText: 'Description', hintText: 'eg cheese pizza'),
              ),
              DropdownButtonFormField<int>(
                value: _ratingController,
                items: [1, 2, 3, 4, 5]
                    .map((label) => DropdownMenuItem(
                          child: Text(label.toString()),
                          value: label,
                        ))
                    .toList(),
                hint: Text('Rating'),
                onChanged: (value) {
                  setState(() {
                    _ratingController = value;
                  });
                },
              ),
            ],
          ),
          actions: <Widget>[
            FlatButton(
              onPressed: () {
                _handleSubmit(_eateryController.text, _supplierController.text,
                    _descriptionController.text, _ratingController);
                Navigator.pop(context);
              },
              child: Text('Save'),
            ),
            FlatButton(
              onPressed: () => Navigator.pop(context),
              child: Text('Cancel'),
            )
          ],
        );
    

    the setState doesn't seem to be dynamically updating the fields value. The updated value will only show once I close and re open the AlertDialog.

    How can I get this to update instantly?

    Thanks

    • diegoveloper
      diegoveloper about 5 years
      that's because you are calling setState from the page which calls AlertDialog. AlertDialog is stateless widget no stateful, you should wrap your DropdownButtonFormField in a StatefulWidget
  • Nifal Nizar
    Nifal Nizar over 3 years
    You save my day
  • JoaoBM
    JoaoBM over 3 years
    Just wanted to thank you very much as this solved my problem.
  • Kamlesh
    Kamlesh almost 3 years
    @CopsOnRoad "value: _ratingController," confused me that how can we pass a controller instance to value attribute. Kindly update your answer to "value: _ratingControllerValue,". Thanks a lot.
  • CopsOnRoad
    CopsOnRoad almost 3 years
    @Kamlesh The OP used int for _ratingController, so to answer him I had to use the same semantics. I understand the controller could be confusing but it's just an int value.