Home > other >  Validate a non-visible field in Flutter Form
Validate a non-visible field in Flutter Form

Time:09-17

I have a Flutter Form with many dropdownformfield and textformfield widgets, validating these is trivial using the validate: method. Validation for visual fields is obvious.

However, in many forms a non-visible element may need to be validated. For instance, if taking a picture in a Form, there will only be a button to take the picture which will input the resulting filename into a String var. I would need to validate the String var in this case and return the validation result to the button (i.e. display a "Required field" below the button), but of course the String var is not held in any formfield widget.

This being said, how can I either "wrap" the button in a widget which contains a validator: method, or how can I add a validator to the button itself AND then display the appropriate validation message to the user in the UI?

Thank you!

CodePudding user response:

You could create your own FormField:

class TakePictureFormField extends FormField<String> {
  /// Creates a [FormField] that contains an [ElevatedButton] to take a picture
  /// with the phone camera.
  ///
  /// The [String] value corresponds to the path of the picture taken.
  TakePictureFormField({
    Key? key,
    String? initialValue,
    FormFieldSetter<String>? onSaved,
    FormFieldValidator<String>? validator,
    bool enabled = true,
    AutovalidateMode? autovalidateMode,
    ButtonStyle? buttonStyle,
    void Function(String)? onChanged,
  }) : super(
          key: key,
          initialValue: initialValue,
          onSaved: onSaved,
          validator: validator,
          enabled: enabled,
          autovalidateMode: autovalidateMode,
          builder: (FormFieldState<String> field) {
            final currentValue = field.value;
            return InputDecorator(
              decoration: InputDecoration(
                border: InputBorder.none,
                errorText: field.errorText,
                errorBorder: OutlineInputBorder(
                  borderSide: BorderSide(
                    color: Theme.of(field.context).errorColor,
                  ),
                ),
              ),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  ElevatedButton(
                    style: buttonStyle,
                    onPressed: () async {
                      // Fake implementation to take a picture.
                      final value = await Future<String>.delayed(
                          const Duration(microseconds: 300),
                          () => 'my_path/to/image');

                      field.didChange(value);
                      if (onChanged != null) {
                        onChanged(value);
                      }
                    },
                    child: const Text('Take a Picture'),
                  ),
                  if (currentValue != null) Text(currentValue),
                ],
              ),
            );
          },
        );
}

And then use it inside a Form like you would for any other FormField widget:

TakePictureFormField(
  validator: (val) =>
    val == null || val.isEmpty ? 'Error invalid picture' : null,
)

Try the complete example on DartPad

  • Related