I'm new to flutter and trying to build a contact form using flutter_form_builder. Based on the selected contact type I want to show different form fields. The adding and removing is working but I get warnings and errors when I want to close the form or when I add validation to the fields. I have added screenshots with the different selections and marked the changing fields. When the contact type is switched I got the following warnings:
flutter: Warning! Replacing duplicate Field for email -- this is OK to ignore as long as the field was intentionally replaced
flutter: Warning! Replacing duplicate Field for invoiceStreet -- this is OK to ignore as long as the field was intentionally replaced
flutter: Warning! Replacing duplicate Field for invoicePostcode -- this is OK to ignore as long as the field was intentionally replaced
flutter: Warning! Replacing duplicate Field for invoiceCity -- this is OK to ignore as long as the field was intentionally replaced
flutter: Warning! Ignoring Field unregistration for invoiceStreet -- this is OK to ignore as long as the field was intentionally replaced
flutter: Warning! Ignoring Field unregistration for invoicePostcode -- this is OK to ignore as long as the field was intentionally replaced
flutter: Warning! Ignoring Field unregistration for invoiceCity -- this is OK to ignore as long as the field was intentionally replaced
And when I navigate back the following error is thrown:
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown while finalizing the widget tree:
'package:flutter_form_builder/src/form_builder.dart': Failed assertion: line 194 pos 12: '_fields.containsKey(name)': is not true.
package:flutter_form_builder/src/form_builder.dart:194
When the exception was thrown, this was the stack
Contact Type Person selected screenshot
Contact Type Company selected screenshot
class ContactForm extends StatefulWidget {
const ContactForm({Key? key}) : super(key: key);
@override
State<ContactForm> createState() => _ContactFormState();
}
class _ContactFormState extends State<ContactForm> {
bool isCompany = false;
bool isShippingAdressNeeded = false;
final GlobalKey<FormBuilderState> _formKey = GlobalKey<FormBuilderState>();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: FormBuilder(
key: _formKey,
autovalidateMode: AutovalidateMode.always,
child: ListView(
children: [
FormBuilderSegmentedControl(
name: kIsCompany,
initialValue: false,
options: const [
FormBuilderFieldOption(
value: false,
child: Text(kContactTypePersonLabel),
),
FormBuilderFieldOption(
value: true,
child: Text(kContactTypeCompanyLabel),
)
],
onChanged: (bool? value) {
if (value != null) {
setState(() {
//_formKey.currentState.unregisterField(name, field)
isCompany = value;
});
}
},
),
if (!isCompany) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: FormBuilderDropdown(
name: kTitle,
initialValue: 1,
decoration: const InputDecoration(
labelText: kTitleLabel,
),
items: const [
DropdownMenuItem(
value: 1,
child: Text('Frau'),
),
DropdownMenuItem(
value: 2,
child: Text('Herr'),
),
DropdownMenuItem(
value: 3,
child: Text('Divers'),
),
],
),
),
const SizedBox(
width: 5,
),
Expanded(
child: FormBuilderTextField(
keyboardType: TextInputType.text,
name: kFirstName,
initialValue: '',
decoration: const InputDecoration(
labelText: kFirstNameLabel,
),
),
),
const SizedBox(
width: 5,
),
Expanded(
child: FormBuilderTextField(
keyboardType: TextInputType.text,
name: kLastName,
initialValue: '',
decoration: const InputDecoration(
labelText: kLastNameLabel,
),
),
),
],
),
] else ...[
const SizedBox(
height: 5,
),
FormBuilderTextField(
keyboardType: TextInputType.text,
name: kCompanyName,
initialValue: '',
decoration: const InputDecoration(
labelText: kCompanyNameLabel,
),
),
],
FormBuilderTextField(
keyboardType: TextInputType.text,
name: kCustomerNumber,
initialValue: '',
decoration: const InputDecoration(
labelText: kCustomerNumberLabel,
),
),
FormBuilderTextField(
keyboardType: TextInputType.phone,
name: kPhoneNumber,
initialValue: '',
decoration: const InputDecoration(
labelText: kPhoneNumberLabel,
),
),
FormBuilderTextField(
keyboardType: TextInputType.emailAddress,
name: kEmail,
initialValue: '',
decoration: const InputDecoration(
labelText: kEmailLabel,
),
),
InvoiceAdress(
formKey: _formKey,
),
const SizedBox(
height: 15,
),
Row(
children: [
const Expanded(
child: Text(
'Lieferadresse',
),
),
Switch(
value: isShippingAdressNeeded,
onChanged: (bool value) {
setState(() {
isShippingAdressNeeded = value;
});
},
),
],
),
if (isShippingAdressNeeded) ShippingAdress(formKey: _formKey),
const SizedBox(
height: 10,
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
final formData = _formKey.currentState!.value;
var contact = Contact.fromMap(formData);
BlocProvider.of<ContactFormBloc>(context)
.add(SavePressedEvent(contact: contact));
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
backgroundColor: Colors.redAccent,
content: Text("Invalid input"),
));
}
},
child: const Text('Speichern'),
),
],
),
),
);
}
}
class ShippingAdress extends StatelessWidget {
final GlobalKey<FormBuilderState> formKey;
const ShippingAdress({Key? key, required this.formKey}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
FormBuilderTextField(
keyboardType: TextInputType.text,
name: kShippingStreet,
initialValue: '',
decoration: const InputDecoration(
labelText: kShippingStreetLabel,
),
),
Row(
children: [
Expanded(
child: FormBuilderTextField(
keyboardType: TextInputType.phone,
name: kShippingPostcode,
initialValue: '',
decoration: const InputDecoration(
labelText: kShippingPostcodeLabel,
),
),
),
const SizedBox(
width: 5,
),
Expanded(
child: FormBuilderTextField(
keyboardType: TextInputType.text,
name: kShippingCity,
initialValue: '',
decoration: const InputDecoration(
labelText: kShippingCityLabel,
),
)),
],
),
],
);
}
}
class InvoiceAdress extends StatelessWidget {
final GlobalKey<FormBuilderState> formKey;
const InvoiceAdress({Key? key, required this.formKey}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 15,
),
const Align(
alignment: Alignment.topLeft,
child: Text(
'Rechnungsadresse',
),
),
FormBuilderTextField(
keyboardType: TextInputType.text,
name: kInvoiceStreet,
initialValue: '',
decoration: const InputDecoration(
labelText: kInvoiceStreetLabel,
),
),
Row(
children: [
Expanded(
child: FormBuilderTextField(
keyboardType: TextInputType.phone,
name: kInvoicePostcode,
initialValue: '',
validator: FormBuilderValidators.integer(errorText: "Es sind nur Zahlen erlaubt"),
decoration: const InputDecoration(
labelText: kInvoicePostcodeLabel,
),
),
),
const SizedBox(
width: 5,
),
Expanded(
child: FormBuilderTextField(
keyboardType: TextInputType.text,
name: kInvoiceCity,
initialValue: '',
decoration: const InputDecoration(
labelText: kInvoiceCityLabel,
),
)),
],
),
],
);
}
}
Library versions: flutter_form_builder: 7.5.0