0

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) {...},

          ),
  • Are you trying to add new items on dropdown and it does showup? and what are you expecting on `member == 'Add New Contact'` – Md. Yeasin Sheikh Feb 01 '23 at 21:07
  • Yes, I am trying to add a new (selected) item to a DropDownButtonField when the user selects the 'Add New Contact' item in that DropDownButtonField. The user then fills out a 'new member' form, which, when submitted, returns the user to the original form with their new member data selected in the DropDownButtonField. – Barry Prentiss Feb 01 '23 at 21:22
  • can you provide full minimal snippet – Md. Yeasin Sheikh Feb 01 '23 at 21:25

1 Answers1

0

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(() {});
            },
          )
        ],
      ),
    );
  }
}
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • Excellent! I'm calling an existing form in a Hero context whose Submit button will (eventually: populate a db with the new data and) return the id and name to the parent form field which will require asynch processing... I'll experiment and return here! – Barry Prentiss Feb 01 '23 at 22:14
  • I think you trying to navigate to new route(page), for that check `Navigator.push` – Md. Yeasin Sheikh Feb 01 '23 at 22:24
  • Absolutely correct @yeasin! My form-calling code: 'onChanged: (member) async { if(member == 'Add New Contact') { Navigator.push(context, MaterialPageRoute( builder: (BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Member Registration')), body: const MemberForm(), ); }, )); }' – Barry Prentiss Feb 03 '23 at 17:10
  • Now trying to return new member id and name to parent form.... – Barry Prentiss Feb 03 '23 at 17:11
  • some place of `MemberForm` you are using navigator.pop. here pass the model. You can check [this](https://stackoverflow.com/a/70324661/10157127) and [navigatorExample](https://stackoverflow.com/a/68605773/10157127) – Md. Yeasin Sheikh Feb 04 '23 at 00:47