Intro: A powerful flutter form widget, easy to use and extend. provide rich API to simplify form control and sync|async validation.
Web Demo
Simple Usage
add dependency
flutter pub add forme
/// add base fields
flutter pub add forme_base_fields
create forme
FormeKey key = FormeKey();// formekey is a global key , also used to control form Widget child = FormeTextField(name:'username',decoration:const InputDecoration(labelText:'Username')); Widget forme = Forme( key:key, child:child, )
Forme Attributes
Attribute | Required | Type | Description |
---|---|---|---|
key | false | FormeKey | a global key, also used to control form |
child | true | Widget | form content widget |
readOnly | false | bool | whether form should be readOnly,default is false |
onValueChanged | false | FormeValueChanged | listen form field’s value change |
initialValue | false | Map<String,dynamic> | initialValue , will override FormField’s initialValue |
onFieldValidationChanged | false | FormeFieldValidationChanged | listen form validation changed |
onValidationChanged | false | FormeValidationChanged | listen form validation change |
onWillPop | false | WillPopCallback | Signature for a callback that verifies that it’s OK to call Navigator.pop |
quietlyValidate | false | bool | if this attribute is true , will not display default error text |
onFocusChanged | false | FormeFocusChanged | listen form field’s focus change |
autovalidateMode | false | AutovalidateMode | auto validate form mode |
autovalidateByOrder | false | bool | whether auto validate form by order |
onFieldsChanged | false | function | listen every field initialled or disposed |
FormeField
attributes supported by all FormeField
Attribute | Required | Type | Description |
---|---|---|---|
name | true | String | field’s id,should be unique in form |
builder | true | FieldContentBuilder | build field content |
readOnly | false | bool | whether field should be readOnly,default is false |
enabled | false | bool | whether field is enabled , default is true |
quietlyValidate | true | bool | whether validate quietly |
asyncValidatorDebounce | false | Duration | async validate debounce , default is 500ms |
autovalidateMode | false | AutovalidateMode | autovalidate mode |
onValueChanged | false | FormeValueChanged | triggered when field’s value changed |
onFocusChanged | false | FormeFocusChanged | triggered when field’s focus state changed |
onValidationChanged | false | FormeFieldValidationChanged | triggered when field’s validation error changed |
onInitialed | false | FormeFieldInitialed | triggered when field initialed |
onSaved | false | FormeFieldSetter | triggered when form saved |
validator | false | FormeValidator | sync validator |
asyncValidator | false | FormeAsyncValidator | async validator |
decorator | false | FormeFieldDecorator | used to decorator a field |
order | false | int | order of field |
requestFocusOnUserInteraction | false | bool | whether request focus when field value changed by user interaction |
registrable | false | bool | whether this field should be registered to Forme |
async validate
async validator is supported after Forme 2.5.0 , you can specific an asyncValidator
on FormeField
, the unique difference between validator
and asyncValidator
is asyncValidator
return a Future<String>
and validator
return a String
when to perform an asyncValidator
if FormeField.autovalidateMode
is AutovalidateMode.disabled
, asyncValidator will never be performed unless you call validate
from FormeFieldController
manually.
if you specific both validator
and asyncValidator
, asyncValidator
will only be performed after validator
return null.
after successful performed an asyncValidator , asyncValidator will not performed any more until field’s value changed
debounce
you can specific a debounce on FormeField
, debounce will not worked when you manually call validate
on FormeFieldController
whether validation itself is valid
in some cases,when an async validation is performing , another validation on same field is performed,in this case ,previous validation is invalid , so if you want to update UI before return validation result in async validator , you need to validate it first,eg:
asyncValidator:(field,value,isValid){ return Future.delayed(const Duration(seconds:2),(){ if(isUnexceptedValue(value)) { if(isValid()){ updateUI(); } return 'invalid'; } return null; }); }
validates
you can use FormeValidates
to simplify your validators
Validator Name | Support Type | When Valid | When Invalid |
---|---|---|---|
notNull | dynamic | value is not null | value is null |
size | Iterable Map String | 1. value is null 2. max & min is null 3. String’s length or Collection’s size is in [min,max] | String’s length or Collection’s size is not in [min,max] |
min | num | 1. value is null 2. value is bigger than min | value is smaller than min |
max | num | 1. value is null 2. value is smaller than max | value is bigger than max |
notEmpty | Iterable Map String | 1. value is not null 2. String’s length or Collection’s size is bigger than zero | 1. value is null 2. String’s length or Collection’s size is zero |
notBlank | String | 1. value is null 2. value.trim()’s length is not null | value’length is zero after trimed |
positive | num | 1. value is null 2. value is bigger than zero | value is smaller than or equals zero |
positiveOrZero | num | 1. value is null 2. value is bigger than or equals zero | value is smaller than zero |
negative | num | 1. value null 2. value is smaller than zero | value is bigger than or equals zero |
negativeOrZero | num | 1. value null 2. value is smaller than or equals zero | value is bigger than zero |
pattern | String | 1. value null 2. value matches pattern | value does not matches pattern |
email | String | 1. value null 2. value is a valid email | value is not a valid email |
url | String | 1. value is null 2. value is empty or value is a valid url | value is not a valid url |
range | num | 1. value null 2. value is in range | value is out of range |
equals | dynamic | 1. value null 2. value is equals target value | value is not equals target value |
any | T | any validators is valid | every validators is invalid |
all | T | all validators is valid | any validators is invalid |
when you use validators from FormeValidates
, you must specific at least one errorText , otherwise errorText is an empty string
FormeKey Methods
whether form has a name field
bool hasField = formeKey.hasField(String name);
whether current form is readOnly
bool readOnly = formeKey.readOnly;
set readOnly
formeKey.readOnly = bool readOnly;
get field’s controller
T controller = formeKey.field<T extends FormeFieldController>(String name);
get form data
Map<String, dynamic> data = formeKey.data;
set form data
formeKey.data = Map<String,dynamic> data;
validate
since 2.5.0 , this method will return a Future ranther than a Map
you can use FormeValidateSnapshot.isValueChanged
to check whether form value is changed duration this validation , if is changed , typically means this validation is invalid , you should not submit your form even though validation is passed
Future<FormeValidateSnapshot> future = formKey.validate({ bool quietly = false, Set<String> names = const {}, bool clearError = false, bool validateByOrder = false, });
get validation
FormeValidation validation = formKey.validation;
reset form
formeKey.reset();
save form
formeKey.save();
whether validate is quietly
bool quietlyValidate = formKey.quietlyValidate;
set quietlyValidate
formeKey.quieltyValidate = bool quietlyValidate;
is value changed after initialed
bool isChanged = formeKey.isValueChanged
get all field controllers (2.5.2)
List<FormeFieldController> controllers = formeKey.controllers;
get fieldListenable
ValueListenable<FormeFieldController> fieldListenable = formeKey.fieldListenable(String name);
get fieldsListenable
ValueListenable<Map<String, FormeFieldController<dynamic>?>> fieldsListenable = formeKey.fieldsListenable;
used to listen every field initialed or disposed of, value is an empty or single sized map , key is the field name, value is FormeFieldController
get validation listenable
ValueListenable<FormeValidation> validationListenable = formeKey.validationListenable;
useful when you want to show or hide a submit button when validation passed or not,eg:
Builder( builder: (context) { return ValueListenableBuilder<FormeValidation>( valueListenable: key.validationListenable, builder: (context, validation, child) { if (!validation.isValidOrUnnecessaryOrEmpty) { return const SizedBox.shrink(); } return yourSubmitButton; }); }, ),
Forme Field Methods
get forme controller
FormeController? formeController = field.formeController;
get field’s name
String name = field.name
whether current field is readOnly
bool readOnly = field.readOnly;
set readOnly on field
field.readOnly = bool readOnly;
whether current field is enabled
bool enabled = field.enabled;
set enabled on field
field.enabled = bool enabled;
get focusNode
FocusNode? focusNode = field.focusNode;
get context
BuilderContext context = field.context;
get focusListenable
ValueListenable<bool> focusListenable = field.focusListenable;
get readOnlyListenable
ValueListenable<bool> readOnlyListenable = field.readOnlyListenable;
get enabledListenable
ValueListenable<bool> enabledListenable = field.enabledListenable;
get value
T value = field.value;
set value
field.value = T data;
reset field
field.reset();
validate field
since 2.5.0 , this method will return a Future ranther than a String
Future<FormeFieldValidateSnapshot> future = field.validate({bool quietly = false});
get validation
FormeFieldValidation validation = field.validation;
get validationListenable
ValueListenable<FormeFieldValidation> validationListenable = field.validationListenable;
get valueListenable
ValueListenable<T> valueListenable = field.valueListenable;
get oldValue
if the value changed , you can use this method to get the previous value
T? value = field.oldValue;
is value changed
bool isChanged = field.isValueChanged
whether is field mounted
bool mounted = field.mounted
get generic type
Type type = field.type;
whether field value is nullable
bool isNullable = field.isNullable;
FocusNode
To simplify form control, Forme does not support set focus node on the field, FocusNode will be auto-created when needed.
custom focus node
if you want to override default focusNode , you can extends FormeFieldState and use set focusNode method to do that, in this case, you must dispose of focusNode by yourself
custom field
FormeField<String>( name: 'customField', initialValue: 'currentValue', builder: (FormeFieldState<String> state) { return TextButton( onPressed: () { state.didChange('newValue'); }, child: Text(state.value), ); }, ),
Download and contribute to this plugin source code on GitHub
Provides the list of the opensource Flutter apps collection with GitHub repository.