Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation event for custom widget

Tags:

flutter

In flutter, a TextFormField for an example, has a validator which can be used for validation:

 TextFormField(validator: validator ...
    

Then in your form, you can call validate on the Form widget to make all children with these validators validate:

_formKey.currentState!.validate()

If a validation fails, the TextFormField will display an error text along with a position and color transition.

I have my own custom photo widget, and I would like to make it able to support the same validation functionality. That is, give it a validator, hook it up to the validate() event, and if the user hasn´t added any photo, the validation fails and shows the error text the validator returns. But I cannot figure out how to implement the validate eventlistener on a custom widget. So how would you go around this?

Update:

@user18309290 pointed me in the direction of extending my widget from FormField. But the problem is that my widget has internal functions and properties I need to access in the instance/layout tree. But I can´t figure out the right way to do it. I could put all the stuff in the build method, but that means that all of my "heavy" logic and properties would be reinstantiated every time the widget rebuilds if I understand correctly. So how do I extend from FormField to have validation support (validation fails if image list is empty), but still have access to my methods and properties?

This is my simplified widget:

class MyPhotoComponent extends FormField<List<File>> {
  late String title;
  List<File> images = [];

  openCamera() {
    print('This and other methods, has alot of logic');
    images.add(File('filepath'));
  }

  String internalTitle = 'Internal title';

  MyPhotoComponent({required String title, required FormFieldSetter<List<File>> onSaved, FormFieldValidator<List<File>>? validator, required List<File> initialValue, Key? key})
      : super(
          onSaved: onSaved,
          validator: validator,
          initialValue: initialValue,
          key: key,
          builder: (FormFieldState<List<File>> state) {
            return Column(
              children: [
                Builder(builder: (BuildContext context) {
                  return Column(
                    children: [
                      Text(internalTitle), //Error: The instance member 'internalTitle' can't be accessed in an initializer.
                      MyOtherPhotoGalleryComponent(images: images), //Error: The instance member 'images' can't be accessed in an initializer.
                      ElevatedButton.icon(
                        onPressed: openCamera, //Error: The instance member 'openCamera' can't be accessed in an initializer.
                        icon: Icon(Icons.add_a_photo),
                        label: Text('Take photo'),
                      ),
                    ],
                  );
                }),
                if (state.hasError) Builder(builder: (BuildContext context) => Text('Validation error'))
              ],
            );
          },
        );
}
like image 570
Farsen Avatar asked Sep 19 '25 16:09

Farsen


1 Answers

Inherit a custom widget from FormField. Each individual form field should be wrapped in a FormField widget like TextFormField.

Form(
  key: _formKey,
  child: Column(
    children: <Widget>[
      TextFormField(
        validator: (String? value) {
          if (value == null || value.isEmpty) {
            return 'Please enter some text';
          }
          return null;
        },
      ),
      CustomFormField(
        validator: (String? value) {
          if (value == null || value.isEmpty) {
            return 'Please select something';
          }
          return null;
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {}
        },
        child: const Text('Submit'),
      ),
    ],
  ),
);
like image 160
user18309290 Avatar answered Sep 22 '25 07:09

user18309290