forme 3.2.3+7 forme: ^3.2.3+7 copied to clipboard
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
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 |
currently supported fields #
Name | Return Value | Nullable |
---|---|---|
FormeTextField | string | false |
FormeDateTimeField | DateTime | true |
FormeNumberField | num | true |
FormeTimeField | TimeOfDay | true |
FormeDateRangeField | DateTimeRange | true |
FormeSlider | double | false |
FormeRangeSlider | RangeValues | false |
FormeFilterChip | List< T> | false |
FormeChoiceChip | T | true |
FormeCheckbox | bool | true |
FormeCheckboxListTile | bool | true |
FormeSwitch | bool | false |
FormeSwitchTile | bool | false |
FormeDropdownButton | T | true |
FormeListTile | List< T> | false |
FormeRadioGroup | T | true |
FormeCupertinoTextField | string | false |
FormeCupertinoDateTimeField | DateTime | true |
FormeCupertinoNumberField | num | true |
FormeCupertinoPicker | int | false |
FormeCupertinoSegmentedControl | T | true |
FormeCupertinoSlidingSegmentedControl | T | true |
FormeCupertinoSlider | double | false |
FormeCupertinoSwitch | bool | false |
FormeCupertinoTimerField | Duration | true |
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 , value is an empty or single sized map , key is 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 value changed , you can use this method to get 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 #
for simplify form control , Forme not support set focus node on 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 focusNode by yourself
TextEditingController #
for simplify form control , set TextEditingController
is not supported on some fields , eg : FormeTextField
,FormeNumberField
,FormeDateTimeField
and etc...
if you want to access underlying TextEditingController
, you can try to convert FormeFieldController
to FormeTextFieldController
or other to do that
custom field #
FormeField<String>(
name: 'customField',
initialValue: 'currentValue',
builder: (FormeFieldState<String> state) {
return TextButton(
onPressed: () {
state.didChange('newValue');
},
child: Text(state.value),
);
},
),