6

I have an alertDialog containing a DropdownButton widget. Whenever I click on an option within the dropDown I want it to display the selected value. I have listed the code below along with 2 screenshots.

I believe this may be an issue with how flutter builds widget because when I placed the DropdownButton widget outside of the dialog it worked, however placing it within an alertDialog causes it to fail. I also noticed that if I clicked on an option in the DropdownButton and then exited and clicked on the dialog again the selected item would change. However, I want the selected value to change without the user having to tap out of the dialog and then back in.

enter image description here

^

The above image is the dialog when a user first clicks on it. At first the only selected item is "I'm not able to help". This value should change whenever a user clicks on the DropdownMenu widget and selects a different option such as "other".

enter image description here

^

These are the various options a user can click on within the dropdown menu. When a user clicks on it, the menu should update accordingly.

CODE:

Please note that I have defined _chosenValue as a global variable outside of the build function.

void _showDecline() {

      showDialog(
        context: context,
        builder: (BuildContext context) {

          return AlertDialog(
            title: new Text("Decline Appointment Request"),
            content: Container(
              height: 100,
              width: 200,
              child: Column(
                children: <Widget>[
                  new Text("Please select an option for why you declined."),
                  new DropdownButton<String>(
                    value: _chosenValue,
                    underline: Container(),
                    items: <String>['I\'m not able to help', 'Unclear description', 'Not available at set date and time', 'Other'].map((String value) {
                      return new DropdownMenuItem<String>(
                        value: value,
                        child: new Text(value, style: TextStyle(fontWeight: FontWeight.w500),),
                      );
                    }).toList(),
                     onChanged: (String value) {
                       setState(() {
                        _chosenValue = value;
                      });
                    },
                  )
                ],
              ),
            ),
            actions: <Widget>[
              // usually buttons at the bottom of the dialog
              new FlatButton(
                child: new Text("Close"),
                onPressed: () {},
                },
              ),
              
            ],
          );
        },
      );
    }
Hudson Kim
  • 416
  • 6
  • 15

5 Answers5

16

setState will only update current StatefulWidget's Widget Build function.

You should use StatefulBuilder inside showDialog.

For your case just add StatefulBuilder as a parent of your DropDown widget, and use StateSetter when you want to update the StatefulBuilder's children. It will only update the widget tree defined under StateFulBuilder builder function.


See the full code including stateFulBuilder at DartPad code StateFulBuilderDartPad.

For more information on StatefulBuilder head over to StateFulBuilder documentation page.

Darshan Rathod
  • 591
  • 4
  • 16
12
import 'dart:convert';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String _chosenValue;

  void _showDecline() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (BuildContext context, StateSetter setState) {
            return AlertDialog(
              title: new Text("Decline Appointment Request"),
              content:
                  Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
                new Text("Please select an option for why you declined."),
                SingleChildScrollView(
                    scrollDirection: Axis.horizontal,
                    child: new DropdownButton<String>(
                      hint: Text('Select one option'),
                      value: _chosenValue,
                      underline: Container(),
                      items: <String>[
                        'I\'m not able to help',
                        'Unclear description',
                        'Not available at set date and time',
                        'Other'
                      ].map((String value) {
                        return new DropdownMenuItem<String>(
                          value: value,
                          child: new Text(
                            value,
                            style: TextStyle(fontWeight: FontWeight.w500),
                          ),
                        );
                      }).toList(),
                      onChanged: (String value) {
                        setState(() {
                          _chosenValue = value;
                        });
                      },
                    )),
              ]),
              actions: <Widget>[
                // usually buttons at the bottom of the dialog
                new FlatButton(
                  child: new Text("Close"),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
              ],
            );
          },
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          child: FlatButton(child: Text('Click'), onPressed: _showDecline),
        ),
      ),
    );
  }
}
shilpa navale
  • 409
  • 3
  • 9
  • 18
5

Just check out the below example you have to use the statefulBuilder to change the state.

import 'dart:convert';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HomePage());
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String _chosenValue;
 
  void _showDecline() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (BuildContext context, StateSetter setState){
            return AlertDialog(
            title: new Text("Decline Appointment Request"),
            content: Container(
              height: 100,
              width: 200,
              child: Column(
                children: <Widget>[
                  new Text("Please select an option for why you declined."),
                  new DropdownButton<String>(
                    hint: Text('Select one option'),
                    value: _chosenValue,
                    underline: Container(),
                    items: <String>[
                      'I\'m not able to help',
                      'Unclear description',
                      'Not available at set date and time',
                      'Other'
                    ].map((String value) {
                      return new DropdownMenuItem<String>(
                        value: value,
                        child: new Text(
                          value,
                          style: TextStyle(fontWeight: FontWeight.w500),
                        ),
                      );
                    }).toList(),
                    onChanged: (String value) {
                      setState(() {
                        _chosenValue = value;
                      });
                    },
                  )
                ],
              ),
            ),
            actions: <Widget>[
              // usually buttons at the bottom of the dialog
              new FlatButton(
                child: new Text("Close"),
                onPressed: () {
                  Navigator.of(context).pop();
                },
              ),
            ],
          );
          },
                  
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
              child: Container(
          child: FlatButton(child: Text('Click'), onPressed: _showDecline),
        ),
      ),
    );
  }
}


Just let me know if it works.

Sagar Acharya
  • 3,397
  • 4
  • 12
  • 34
1

Try This ......

implement the alert on separate dart file and call it. that worked for me.

Important - there was used following dropdown plugin because that ui better for me... Link - dropdown_button2: ^1.2.2

on main page call to the alert as follows.

import 'package:crmapp/pages/payment_history/payment_history_search_dialog.dart';
import 'package:flutter/material.dart';

class PaymentHistoryScreen extends StatefulWidget {
  @override
  _PaymentHistoryScreenState createState() => _PaymentHistoryScreenState();
}

class _PaymentHistoryScreenState extends State<PaymentHistoryScreen> {
  ScrollController scrollController = new ScrollController();
 
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // Setting up AppBar
      appBar: AppBar(
        title: Text('Payment History'),
      ),

      // Body
      body: Container(
        // your code here - you can use onpressed method in the body also.here I used it for floating button
        ),
      ),
      floatingActionButton: FloatingActionButton(
          onPressed: () {
            showDialog(
                barrierDismissible: false,
                context: context,
                builder: (BuildContext context) {
                  return new PaymentHistorySearchDialog(); //call the alert dart 
                }
            );
          },
          child: Container
            (
              decoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(100)),
              ),
              child: Icon(Icons.search_sharp, size: 32, color: Colors.white,)
          )
      ),
    );
  }

 

then code the alert dart as follows.

import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class PaymentHistorySearchDialog extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return PaymentHistorySearchDialogState();
  }
}

class PaymentHistorySearchDialogState extends State<PaymentHistorySearchDialog> {

  String? selectedValue;
  List<String> items = [
    'All',
    'Completed',
    'Pending',
    'Rejected',
  ];

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

  @override
  Widget build(BuildContext context) {
    return new AlertDialog(
        titlePadding: EdgeInsets.only(top: 20, left: 15, right: 15, bottom: 5),
        contentPadding: EdgeInsets.only(
            top: 15,
            left: 15,
            right: 15,
            bottom: 5
        ),
        title: Text(
            'Search'.toUpperCase(),
            style: TextStyle(
              color: Colors.black,
              fontSize: 22,
              fontWeight: FontWeight.w600,
              fontFamily: "medium",
            )
        ),
        content: Container(
          width: double.infinity,
          height: 220,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              DropdownButtonHideUnderline(
                child: DropdownButton2(
                  hint: Text(
                    'Select Status',
                    style: TextStyle(
                      fontSize: 14,
                    ),
                  ),
                  items: items
                      .map((item) =>
                      DropdownMenuItem<String>(
                        value: item,
                        child: Text(
                          item,
                          style: const TextStyle(
                            fontSize: 14,
                          ),
                        ),
                      ))
                      .toList(),
                  value: selectedValue,
                  onChanged: (value) {
                    setState(() {
                      selectedValue = value as String;
                      //Navigator.of(context).pop();
                    });
                    print(value);

                    // selectedValue = value as String;
                  },
                  buttonHeight: 30,
                  buttonWidth: double.infinity,
                  itemHeight: 40,
                  buttonDecoration: BoxDecoration(
                    // borderRadius: BorderRadius.circular(14),
                    border: Border(
                      bottom: BorderSide(width: 1, color: Colors.black38),
                    ),
                  ),
                  buttonPadding: const EdgeInsets.only(bottom: 5, top: 5),

                ),
              )
            ],
          ),
        )
    );
  }
}
0
  onTap: () {
          ///___________________________________________________________________
          // Get.defaultDialog(
          //   title: " وضعیت دزدگیر",
          //   middleText: "پیام اعلام وضعیت دزدگیر ارسال گردد؟",
          //   titleStyle: TextStyle(
          //       color: mainColor2, fontWeight: FontWeight.bold, fontSize: 16),
          //   middleTextStyle:
          //   TextStyle(color: mainColor6.withOpacity(0.9), fontSize: 15),
          // );
          ///----------------------------------------------------------------------
          // showDialog(
          //     context: context,
          //     builder: (context) => AlertDialog(
          //       content: Column(
          //         children: <Widget>[
          //           TextField(
          //             decoration: InputDecoration(
          //               icon: Icon(Icons.account_circle),
          //               labelText: 'Username',
          //             ),
          //           ),
          //           TextField(
          //             obscureText: true,
          //             decoration: InputDecoration(
          //               icon: Icon(Icons.lock),
          //               labelText: 'Password',
          //             ),
          //           ),
          //         ],
          //       ),
          //     ),
          // );
          ///___________________________________________________________________
          List<DropdownMenuItem<String>> listDrop = [];
          String selected=null;
          void loadData() {
            listDrop.add(new DropdownMenuItem(
              child: new Text("پایدار"),
              value:"555",
            ));
            listDrop.add(
              new DropdownMenuItem(
                child: new Text("لحظه ای"),
                value:"444",
              ),
            );
          }
          loadData();

          Alert(
              context: context,
              title: "تنظیمات خروجی شماره ۱",
              // desc: ".",
              // image: Image.asset(
              //   "assets/settings.png",
              //   scale: 5,
              // ),
              content: Directionality(
                textDirection: TextDirection.rtl,
                child: Center(
                  child: Column(
                    children: <Widget>[
                      SizedBox(height: 20.0),
                      TextField(
                        keyboardType: TextInputType.text,
                        controller: _codeShargController,
                        decoration: InputDecoration(
                          labelText: 'نام خروجی',
                          hintText: '${out1.read('codeShargController')}',
                        ),
                      ),
                      SizedBox(height: 25.0),
                      Center(


                        child: DropdownButton(
                          underline: Container(
                            height: 1.5,
                            color: Colors.black26,
                          ),
                          hint: Text("وضعیت عملکرد"),
                          items: listDrop,
                          isExpanded: true,
                          value: selected,
                          style: TextStyle(color: Colors.black, fontSize: 16),
                          onChanged: (newValue)  {
                            selected = newValue;
                           // setState(() {});
                            setState(() { selected = newValue; });

                          },
                        ),





                      ),
                      SizedBox(height: 25.0),
                    ],
                  ),
                ),
              ),
              // content: Column(
              //   children: <Widget>[
              //
              //     SizedBox(height: 10.0),
              //
              //     TextField(
              //
              //       decoration: InputDecoration(
              //
              //         icon: Icon(Icons.account_circle),
              //         labelText: 'Username',
              //       ),
              //     ),
              //     SizedBox(height: 10.0),
              //
              //     TextField(
              //       obscureText: true,
              //       decoration: InputDecoration(
              //         icon: Icon(Icons.lock),
              //         labelText: 'Password',
              //       ),
              //     ),
              //   ],
              // ),
              buttons: [
                DialogButton(
                  onPressed: () {
                    out1.write(
                        "codeShargController", _codeShargController.text);

                    Navigator.pop(context);
                  },
                  child: Text(
                    "ثبت",
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                )
              ]).show();

          ///___________________________________________________________________
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83