flutter

Extending from FormField in a Stateful Widget


Extending from FormField in a Stateful Widget

I have a Stateful widget with properties and functions. I would like to extend the widget from FormField, because I need to validate some user input on the widget.

It seems that it is not possible to extend from multiple classes (StatefulWidget and FormField).

If I try to create a normal class that extends from FormField:

class CustomInput extends FormField<bool> {
  final Widget label;
  final void Function(bool?) onChanged;

  userClicked() {
    print('User clicked');
  }

  CustomInput({
    required this.label,
    required this.onChanged,
    FormFieldValidator<bool>? validator,
  }) : super(
          validator: validator,
          builder: (field) {           
            return Column(
              children: [
                TextButton(
                  onPressed: () => userClicked(), //<-- The instance member 'userClicked' can't be accessed in an initializer.
                  child: Text('Call internal function'),
                ),
            

... then I cannot access internal methods because of the 'The instance member 'userClicked' can't be accessed in an initializer.' error.

So how do you create a widget that extends from FormField to use the validator, onChanged, onSaved etc., but at the same time have internal logic that can be accessed normally from the widget tree?


Solution

  • Instead of extending FormField, the solution was to return a FormField from the StatefulWidget. In this example the validation content is a string array, but it can of course be whatever:

    class CustomInput extends StatefulWidget {
      final String? Function(List<String>)? validator;
      final Function(List<String>)? onChanged;
    
      const CustomInput({this.onChanged, this.validator, Key? key}) : super(key: key);
    
      @override
      State<CustomInput> createState() => _CustomInputState();
    }
    
    class _CustomInputState extends State<CustomInput> {
    
      @override
      void initState() {
        super.initState();
      }
      
     userClicked() {
        print('User clicked');
      }
    
      @override
      Widget build(BuildContext context) {
        return FormField(validator: ((value) {
          if (widget.validator != null) {
            return widget.validator!(widget.imagePaths);
          }
          return null;
        }), builder: (FormFieldState<List<String>> state) {
          return Column(
                  children: [
                    TextButton(
                      onPressed: () => userClicked(), //<-- The instance member 'userClicked' can't be accessed in an initializer.
                      child: Text('Call internal function'),
                    ),
                    ]
              );
            
        });
      }
    }