flutter multiSelectDropDown form field state not recognize by parent Form

22 views Asked by At

In context of a FormBuilder Flutter that contains many custom Fields, I would like to add multiSelectDropDown (based on this package : https://pub.dev/packages/multi_dropdown)

The generation of UI field and select behaviour seems to be run correctly.

But when I validate my form, the data into this widget is not recognize by the parent form.

I try to :

  • extends FormField class
  • add the main form key from the parent to child
  • create new form key for this child

I never can retrieve value of the widget. It's strange for me because I already created another custom widget form and value are automatically retrieve by the main form widget into validation (perhaps because other widgets are created from flutter_form_builder and other not).

This is the main Form :

class EditOperationFormState extends State<EditOperationForm>
{
  final formKey    = GlobalKey<FormBuilderState>();

  @override
  Widget build(BuildContext context)
  {
    return FormBuilder
    (
      key: formKey,
      child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Padding(padding: EdgeInsets.only(top: 20)),
          Text('Custom Label', style: MyText.textStandardWhite),
          FormBuilderTextField
          (
            name: 'custom_label',
            initialValue: widget.initialvalues?['custom_label'],
            decoration: const InputDecoration(
              prefixIcon: Icon(Icons.new_label),
              hintText:   'xxxxxxxxxxxxxx',
              labelText:  'xxxxxxxxxxxxxxx',
              hintStyle:  TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              labelStyle: TextStyle(fontSize: 13, color: Colors.grey),
              focusedBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.purple)),
              enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: Colors.grey, width: 1.0)
              ),
            ),
            style: MyText.textStandardBlue,
          ),

          Expanded(
            child: Row(children: [
                Expanded(child: FooBarDropdown(items: foobars, initialValue: widget.initialvalues?['foo_bar'])),
                const SizedBox(width: 50),
                Expanded(child: CategoryDropdown(items: categories, initialValue: widget.initialvalues?['category'])),
            ]),
          ),

          Expanded(
            child: Row(children: [
                Expanded(child: ItemDropdown(items: tools, initialValue: widget.initialvalues?['tools'])),
                const SizedBox(width: 50),
                Expanded(child: MultiselectDropdownForm()),
            ]),
          ),

          Expanded(
            child: Row(children: [
                Expanded(child: TextFormField(decoration: const InputDecoration(border: UnderlineInputBorder(), labelText: 'Note', hintText: '', floatingLabelBehavior: FloatingLabelBehavior.always))),
            ]),
          ),

          const Padding(padding: EdgeInsets.only(top: 30)),
          Row(children: [
            ElevatedButton(onPressed: () {postForm(formKey, widget.initialvalues);}, child: const Text('Save')),
            ElevatedButton(onPressed: () {Navigator.pop(context);}, child: const Text('Cancel'))
          ]),
        ],
      ),
    );
  }
}

This is the form field that data not go up :

class MultiselectDropdownFormState extends State<MultiselectDropdownForm>
{
    @override
    Widget build(BuildContext context)
    {
        return FormField
        (
            initialValue: 'fezfzfezfz',
            builder: (FormFieldState<String> field)
            {
                return FutureBuilder
                (
                    future: getData(),
                    builder: (context, snapshot)
                    {
                        if (snapshot.connectionState == ConnectionState.done)
                        {
                            if (snapshot.data != null)
                            {
                                List<String> assignments = snapshot.data!;

                                return MultiSelectDropDown
                                (
                                    options: [
                                        for (var assign in assignments) ValueItem(label: assign, value: assign)
                                    ],
                                    selectionType: SelectionType.multi,
                                    chipConfig: const ChipConfig(wrapType: WrapType.wrap),
                                    dropdownHeight: 300,
                                    optionTextStyle: const TextStyle(fontSize: 12),
                                    selectedOptionIcon: const Icon(Icons.check_circle), 
                                    onOptionSelected: (List<ValueItem<String>> selectedOptions) {  },
                                );
                            }
                            else
                            {
                                return const Text('');
                            }
                        }
                        else
                        {
                          return const Text('');
                        }
                    },
                );
            },
        );
    }

    Future<List<String>> getData() async
    {
        List<String> assignments = await fooBarRepository.getAllAssignments();

        return assignments;
    }
}

Example of custom widget that go up data correctly (in the same form issue) :

class FooBarDropdown extends StatefulWidget
{
  final Future<List<FooBar>> items;

  final int? initialValue;

  const FooBarDropdown({super.key, required this.items, this.initialValue});

  @override
  State<FooBarDropdown> createState() => FooBarDropdownState();
}

class FooBarDropdownState extends State<FooBarDropdown>
{
  late int? selectedItem = 1;

  @override
  Widget build(BuildContext context)
  {
    return FutureBuilder
    (
      future: widget.items,
      builder: (context, snapshot) {

        List? data = snapshot.data ?? [];

        return FormBuilderDropdown
        (
          name: 'FooBar',
          isExpanded: false,
          dropdownColor: Colors.red,
          initialValue: widget.initialValue,
          items: data.map((e) => DropdownMenuItem(value: e.id, child: Text(e.label.toString()))).toList(),
          onChanged: (value) {
            setState(() {
              selectedItem = value as int?;
            });
          },
          decoration: const InputDecoration(labelText: 'Select a FooBar', border: OutlineInputBorder()),
        );
      }
    );
  }
}

What is the strategy that I need to use for go up data widget that is not standard ?

  • work around the formKey
  • work around the FormField class
  • others

Thank you for your contribution...

0

There are 0 answers