Last updated:
0 purchases
fpformz
FPFormz #
Functional input validation library based on Fpdart,
which is inspired by Formz.
Features #
For the most part, FPFormz is similar to the original Formz library, with a few notable differences:
FPFormz allows specifying different types for input and validated values, which can be convenient
when using non-string type values (e.g. int, enum, value class, etc.).
It exposes validated values and errors as functional constructs such as Either or Option,
making it easier to manipulate them declaratively.
It also provides a way to write validation logic as mixins, which you can combine to handle more
complex use cases.
Installation #
You can install PFFormz by adding the following entry in your pubsec.yaml:
# pubspec.yaml
dependencies:
fpformz: ^0.1.3
copied to clipboard
Getting Started #
FormInput And Its Derivatives #
To define a validatable input, you need to write a class that extends FormInput<V, I, E> whose
generic parameters correspond to the type of resulting value, input value, and potential errors,
respectively:
class AgeInput extends FormInput<int, String, ValidationError> {
const AgeInput.pristine(name, value) : super.pristine(name, value);
const AgeInput.dirty(name, value) : super.dirty(name, value);
Either<ValidationError, int> validate(String value) =>
Either.tryCatch(() => int.parse(value),
(e, s) => ValidationError(name, '$name should be a number.'));
}
copied to clipboard
After declaring your input, you can use either pristine or dirty constructor to create an
instance:
void example() {
// To create an unmodified ('pristine') input instance:
final age = AgeInput.pristine('age', '');
// Or you can create a modified ('dirty') input instance as below:
final editedAge = AgeInput.dirty('age', '23');
print(age.isPristine); // returns 'true'
print(editedAge.isPristine); // returns 'false'
}
copied to clipboard
You can access validation information either as a functional construct, or as a nullable:
void example() {
print(editedAge.isValid); // returns true
print(editedAge.result); // returns Right(23)
print(editedAge.resultOrNull); // returns 23
print(editedAge.error); // returns None
print(editedAge.errorOrNull); // returns null
print(age.isValid); // returns false
print(age.result); // returns Left(ValidationError)
print(age.resultOrNull); // returns null
print(age.error); // returns Some(ValidationError)
print(age.errorOrNull); // returns ValidationError
}
copied to clipboard
And because most input components treat the user input as a String instance, you can simplify the
type signature by extending from StringFormInput:
class NameInput extends StringFormInput<String, ValidationError> {
const NameInput.pristine(name, value) : super.pristine(name, value);
const NameInput.dirty(name, value) : super.dirty(name, value);
@override
String convert(String value) => value;
@override
Either<ValidationError, String> validate(String value) =>
value.isEmpty
? Either.left(ValidationError(name, 'The name cannot be empty.'))
: super.validate(value);
}
copied to clipboard
Form #
Like with Formz, you can create a form class to host multiple input fields and validate them
together:
class RegistrationForm extends Form {
final NameInput name;
final EmailInput email;
const RegistrationForm({
this.name = const NameInput.pristine('name', ''),
this.email = const EmailInput.pristine('email', '')
});
@override
get inputs => [name, email];
}
copied to clipboard
Then you can validate it using a similar API like that of FormInput:
void example() {
final form = RegistrationForm();
print(form.isPristine); // returns true
print(form.isValid); // returns false
print(form.result); // it 'short circuits' at the first error encountered
print(form.errors); // but you can get all errors this way.
}
copied to clipboard
Form.result returns a map of all validated input values which you can use to invoke a service
method:
void example() {
final form = RegistrationForm();
final params = form.resultOrNull;
service.register(params[form.email.name], params[form.password.name]);
// Or even like this, provided that the input names match those of the parameters:
Function.apply(service.register, [], params);
}
copied to clipboard
Mixins #
You can also write reusable validation logic as a mixin:
@immutable
mixin NonEmptyString<V> on FormInput<V, String, ValidationError> {
ValidationError get whenEmpty => ValidationError(name, 'Please enter $name.');
@override
Either<ValidationError, V> validate(String value) =>
value.isEmpty ? Either.left(whenEmpty) : super.validate(value);
}
copied to clipboard
And build a concrete input field by adding them to either BaseFormInput or StringFormInput as
shown below:
class EmailInput extends StringFormInput<Email, ValidationError>
with EmailString, NonEmptyString {
const EmailInput.pristine(name, value) : super.pristine(name, value);
const EmailInput.dirty(name, value) : super.dirty(name, value);
@override
Email convert(String value) => Email.parse(value);
}
copied to clipboard
It's recommended to split each validation logic into a separate mixin rather than putting all into
an input class to maximise code reuse and achieve separation of concerns (i.e. the 'S'
in SOLID principles).
FPFormz also ships with a small collection of ready-to-use mixins like NonEmptyString
, StringShorterThan, which might be expanded in future versions.
Additional Information #
You can find more code examples in
our test cases.
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.