Adding/Removing FormFields dynamically Flutter_Form_Builder

Viewed 15

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

0 Answers
Related