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...