Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FormBuilderState: setInternalFieldValue #24

Open
2 of 7 tasks
charlieforward9 opened this issue Feb 20, 2025 · 0 comments
Open
2 of 7 tasks

FormBuilderState: setInternalFieldValue #24

charlieforward9 opened this issue Feb 20, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@charlieforward9
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Package/Plugin version

0.5.0 + #23

Platforms

  • Android
  • iOS
  • Linux
  • MacOS
  • Web
  • Windows

Flutter doctor

Flutter doctor

Minimal code example

Code sample
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';

import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_cupertino_fields/form_builder_cupertino_fields.dart';
import 'package:intl/intl.dart';

class ProfileForm extends StatefulWidget {
  const ProfileForm({super.key});

  @override
  State<ProfileForm> createState() => _ProfileFormState();
}

class _ProfileFormState extends State<ProfileForm> {
  final _formKey = GlobalKey<FormBuilderState>();
  TextEditingController firstNameController = TextEditingController();
  TextEditingController lastNameController = TextEditingController();
  TextEditingController emailController = TextEditingController();
  TextEditingController dobController =
      TextEditingController(text: DateTime.now().toIso8601String());
  TextEditingController heightController = TextEditingController();
  TextEditingController weightController = TextEditingController();

  void handleAutofill() {
    setState(() {
      firstNameController.text = "Sample";
      lastNameController.text = "Profile";
      emailController.text = "[email protected]";

      //FIXME: Form not updating the non-textual fields

      // _formKey.currentState?.setInternalFieldValue("Birth Date", "2000-01-01");
      // _formKey.currentState?.setInternalFieldValue("Height", "60\"");
      // _formKey.currentState?.setInternalFieldValue("Weight", "160\"");
      dobController.text = "2000-01-01";
      heightController.text = "60";
      weightController.text = "160";
    });
  }

  void handleFormSubmit() {
    //TODO <are you sure this data is correct?> modal
    try {
      if (_formKey.currentState?.validate() ?? false) {
        _formKey.currentState?.save();
        print("Done");

        setState(() {
          firstNameController.clear();
          lastNameController.clear();
          dobController.clear();
          heightController.clear();
          emailController.clear();
        });
      }
    } catch (e) {
      print(e);
      rethrow;
    }
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: SingleChildScrollView(
        clipBehavior: Clip.none,
        padding: EdgeInsets.only(
          bottom: MediaQuery.of(context).viewInsets.bottom,
        ),
        child: FormBuilder(
          key: _formKey,
          autovalidateMode: AutovalidateMode.onUnfocus,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            //TODO: add a reset button
            crossAxisAlignment: CrossAxisAlignment.center,

            children: [
              const Text(
                "New Patient Profile Form",
                textAlign: TextAlign.center,
              ),
              FormBuilderCupertinoTextField(
                name: "First Name",
                controller: firstNameController,
                keyboardType: TextInputType.name,
                placeholder: "First Name",
                validator: (value) => value == null || value.isEmpty
                    ? "Please enter a first name"
                    : null,
              ),
              FormBuilderCupertinoTextField(
                name: "Last Name",
                controller: lastNameController,
                keyboardType: TextInputType.name,
                placeholder: "Last Name",
                validator: (value) => value == null || value.isEmpty
                    ? "Please enter a last name"
                    : null,
              ),
              FormBuilderCupertinoTextField(
                name: "Email",
                controller: emailController,
                keyboardType: TextInputType.emailAddress,
                placeholder: "Email",
                validator: (value) => value == null ||
                        value.isEmpty ||
                        !value.contains('@') ||
                        !value.contains('.')
                    //TODO: add a regex for email validation
                    ? "Please enter an email"
                    : null,
              ),
              FormBuilderCupertinoDateTimePicker(
                name: "Birth Date",
                controller: dobController,
                inputType: InputType.date,
                format: DateFormat("MMM dd, yyyy"),
                initialValue:
                    DateTime.tryParse(dobController.text) ?? DateTime.now(),
                prefix: const Text("Date of Birth"),
                textAlign: TextAlign.center,
                onChanged: (date) {
                  // the user should only be able to put the date, and this value should be interpreted at UTC and never converted to locale time
                  setState(() => dobController.text =
                      date?.toUtc().toIso8601String().split('T').first ?? '');
                },
                validator: (value) {
                  //if its within the last 10 years its probably a mistake
                  final min = DateTime.now().year - value!.year < 10;
                  final max = DateTime.now().year - value.year > 120;

                  if (min || max) {
                    return 'Please select a valid birth date';
                  }
                  return null;
                },
              ),
              FormBuilderCupertinoSlider(
                name: "Height",
                min: 36,
                max: 99,
                divisions: 63,
                initialValue: double.tryParse(heightController.text) ?? 60,
                prefix: const Text(
                  "Height ",
                ),
                onChanged: (value) =>
                    setState(() => heightController.text = value.toString()),
                minValueWidget: (string) => Container(),
                maxValueWidget: (string) => Container(),
                valueWidget: (value) {
                  final v = int.parse(value);
                  final meters = v * 0.0254;
                  //convert to XftXXin (m)
                  return Text(
                    "${v ~/ 12}ft${v % 12}in / ${meters.toStringAsFixed(2)} m",
                  );
                },
              ),
              FormBuilderCupertinoSlider(
                name: "Weight",
                min: 70,
                max: 400,
                divisions: 330,
                initialValue: double.tryParse(weightController.text) ?? 100,
                prefix: const Text(
                  "Weight ",
                ),
                onChanged: (value) =>
                    setState(() => weightController.text = value.toString()),
                minValueWidget: (string) => Container(),
                maxValueWidget: (string) => Container(),
                valueWidget: (value) {
                  final v = int.parse(value);
                  // Since this is now for weight, we'll convert to kg instead of height calculations
                  final kg = v * 0.453592;
                  // Show weight in lbs and kg
                  return Text(
                    "$v lbs / ${kg.toStringAsFixed(2)} kg",
                  );
                },
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    kDebugMode
                        ? CupertinoButton(
                            onPressed: handleAutofill,
                            child: const Text(
                              "Autofill",
                            ))
                        : Container(),
                    CupertinoButton(
                      onPressed: handleFormSubmit,
                      child: const Text("Next"),
                    ),
                  ],
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
}

Current Behavior

Clicking Autofill will only update the state of the FormBuilderCupertinoTextField's and none other. Clicking save afterwards will show validation errors for the FormBuilderCupertinoDateTimePicker, even though the text is being updated, and the FormBuilderCupertinoSegmentedControl/FormBuilderCupertinoSlider do not even show an updated positioning at all.

Expected Behavior

State should be updated with controller.value or controller.text or setInternalFieldValue

Steps To Reproduce

  1. run ProfileForm in a Flutter app
  2. Click AutoFill
  3. Observe inactivity of sliders (BUG)
  4. Click Next
  5. Observe validation errors (BUG)

Aditional information

No response

@charlieforward9 charlieforward9 added the bug Something isn't working label Feb 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant