Change Values of Dropdown in Dialog in Flutter

Imagine you have a widget that needs to obtain some data from an asynchronous call in a dialog. The problem is that by the time the data arrives, the data would be ignored. StatefulBuilder is designed to help with cases like this by allowing you to specify a builder function that will be invoked every time the async call returns new data. This way, you can ensure that your widget always gets updated when there is new data. In addition, StatefulBuilder also provides a convenient way to update the widget’s state in response to any event.

When you change a DropDownButton widget’s value on a dialog, the new values won’t be reflected in the UI. That’s why you need to wrap the Dialog within a StatefulBuilder.

class ExamplePage extends StatefulWidget {
  const ExamplePage({Key? key}) : super(key: key);

  @override
  State<ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<ExamplePage> {
  String _chosenValue = "Dart";
  final List<String> _choices = ['Dart', 'Kotlin', 'TypeScript', 'Go', 'Java', 'C'];

  _showDialog() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return AlertDialog(
              title: const Text("Favorite Language"),
              content: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [
                const Text("Please select your favorite language."),
                SingleChildScrollView(
                    scrollDirection: Axis.horizontal,
                    child: DropdownButton<String>(
                      hint: const Text('Select one language'),
                      value: _chosenValue,
                      underline: Container(),
                      items: _choices.map((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(
                            value,
                            style: const TextStyle(fontWeight: FontWeight.bold),
                          ),
                        );
                      }).toList(),
                      onChanged: (String? value) {
                        setState(() {
                          _chosenValue = value!;
                        });
                      },
                    )),
              ]),
              actions: <Widget>[
                OutlinedButton(
                  child: const Text("Close"),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            );
          },
        );
      },
    );
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("DropDown in Dialog"),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [OutlinedButton(onPressed: _showDialog, child: Text("Open dialog"))],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _showDialog,
        tooltip: 'Extract',
        child: const Icon(Icons.outbox_outlined),
      ), 
    );
  }
}