flutterdartdropdownbutton

How to call a form from an 'Add New' DropdownButtonFormField


I'm a degreed 25 yr computer scientist but new to Flutter and mobile apps in general.

I am building forms now and want to append an 'Add New' item at the bottom of a list of existing members in a DropDownButtonFormField. If a user selects the 'Add New' item, I'd like to call a 'Register New Member' form for them to fill out. When submitted, I'd like to return the user to the original form, populate the new member info into the field they were working on, and continue with the rest of the form. Sounds reasonable, right?

The only thing I've tried thus far is using the onChanged: event using a Hero as shown below.
This doesn't call the MemberForm() at all, but does populate 'Add New Contact' in the field.
I use this same Hero approach when adding new members from a Button and it works fine.

Any help would be appreciated!

          DropdownButtonFormField(
            decoration: InputDecoration(...),
            value: mainContact,
            style: const TextStyle(fontSize: 20, color: Colors.black54),

            items: members
                .map((member) => DropdownMenuItem<String>(
                      value: member,
                      child: Text(member),
                    ))
                .toList(),
            
            onChanged: (member) =>
              member == 'Add New Contact' ?
              const Hero(tag: 'Hero-Member', child: MemberForm()) :
              setState(() => mainContact = member),
            
            validator: (value) {...},

          ),

Solution

  • It depends on UX how you like to add new item. but make sure to await and then setState to update main ui. This demo will show the flow with modalBottomSheet

    class TestWidget extends StatefulWidget {
      const TestWidget({super.key});
    
      @override
      State<TestWidget> createState() => _TestWidgetState();
    }
    
    class _TestWidgetState extends State<TestWidget> {
      List<String> items = ['Add New Contact', "A", "B"];
      String? mainContact;
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            children: [
              DropdownButtonFormField(
                items: items
                    .map(
                      (e) => DropdownMenuItem(
                        value: e,
                        child: Text(e),
                      ),
                    )
                    .toList(),
                onChanged: (member) async {
                  if (member == 'Add New Contact') {
                    const Hero(tag: 'Hero-Member', child: Text("MemberForm"));
    
                    final TextEditingController controller =
                        TextEditingController();
                    final String newData = await showModalBottomSheet(
                        context: context,
                        builder: (context) => Column(
                              children: [
                                TextField(
                                  controller: controller,
                                ),
                                ElevatedButton(
                                  onPressed: () {
                                    Navigator.of(context).pop(controller.text);
                                  },
                                  child: Text("Save"),
                                ),
                              ],
                            ));
    
                    //you can also get text directly from `controller`
                    if (newData.isNotEmpty) {
                      items.add(newData);
                    }
                  }
    
                  mainContact = member;
                  setState(() {});
                },
              )
            ],
          ),
        );
      }
    }