easy_validation 0.0.3

  • Readme
  • Changelog
  • Installing
  • 71

Easy Validation #

EasyValidation provides many validators for Flutter, based on Dart plugin Respectable.

Get started #

First, you need to add the following dependencies to your 'pubspec.yaml':

  reflectable: any
  build_runner: any
  easy_validation: any

How to use validators and validate a model #

Here is a simple usage example. Note that a lot of examples are available in unit test file test/easy_validation_test.dart.

How to define a class model with validation:

import 'package:easy_validation/easy_validation.dart';

class MyModel {
  MyModel(this.firstname, this.lastname, this.gender, this.birthday, this.dateOfDeath);
  @Required(error: 'Firstname is required')
  @StringLength(min: 3, max: 32, error: 'Firstname must have between 3 and 32 characters')
  final String firstname;
  @Required(error: 'Lastname is required')
  @StringLength(min: 3, max: 32, error: 'Lastname must have between 3 and 32 characters')
  final String lastname;

  @Required(error: 'Gender is required')
  @StringLength(min: 1, max: 1, error: 'Gender must have 1 character')
  final String gender;

  @Required(error: 'Birthday is requried')
  @DateTimeRange(min: '1900-01-01', max: null, error: 'Birthday must be betwwen 1900/01/01 and infinity')
  final DateTime birthday;

  @DateTimeRange(min: '1900-01-01', max: null, error: 'DateOfDeath must be betwwen 1900/01/01 and infinity')
  @GreaterOrEqualTo(propertyName: 'birthday', error: 'DateOfDeath must be greater than Birthday')
  final DateTime dateOfDeath;

Each time you add a validator and each time you update your model class, you must regenerate a mapping file of your models and validators. If this file is not generated and update after any change, EasyValidation won't work !

Use this command line to get the file to get a new file named *.reflectable.dart into a flutter package project.

> flutter packages pub run build_runner build

Use this command line to get the file to get a new file named *.reflectable.dart into a flutter application project.

> flutter pub run build_runner build

How to validate a model:

  • Import the generated mapping file.
  • Call initializeReflectable funtion.
import 'package:easy_validation/easy_validation.dart';
import 'package:*.reflectable.dart';


MyModel tester = new MyModel('Maxime', 'AUBRY', 'M', DateTime.parse('1986-12-22'), null);
bool isValid = ModelState.isValid<MyModel>(tester);

if (isValid) {
  // do stuff...
} else {

Practice usage for Flutter with Blocs:

Here is the authentication_form.dart file:

class AuthenticationForm extends StatefulWidget {
  _AuthenticationFormState createState() => _AuthenticationFormState();

class _AuthenticationFormState extends State<AuthenticationForm> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  AuthenticationFormBloc _authenticationFormBloc;

  void initState() {
    _authenticationFormBloc = BlocProvider.of<AuthenticationFormBloc>(context);

  void dispose() {

  Widget build(BuildContext pageContext) {
    return MultiBlocListener(
      listeners: [
        // ...
      child: BlocBuilder<AuthenticationFormBloc, AuthenticationFormState>(
        builder: (BuildContext context, AuthenticationFormState state) {
          return Form(
            child: Padding(
              padding: EdgeInsets.all(15),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>
                  EmailInput(controller: _emailController),
                  PasswordInput(controller: _passwordController),

  // Events
  void _onEmailChanged() {
        .dispatch(EmailChangedEvent(email: _emailController.text));

  void _onPasswordChanged() {
        .dispatch(PasswordChangedEvent(password: _passwordController.text));

Here is the email_input.dart:

class PasswordInput extends StatelessWidget {
    @required this.controller,

  final TextEditingController controller;

  Widget build(BuildContext context) {
    final AuthenticationFormBloc _authenticationFormBloc =

    return BlocBuilder<AuthenticationFormBloc, AuthenticationFormState>(
      bloc: _authenticationFormBloc,
      builder: (BuildContext context, AuthenticationFormState state) {
        return TextFormField(
          decoration: InputDecoration(
            icon: Icon(
              color: Colors.grey,
            suffixIcon: IconButton(
              icon: Icon(
                color: Colors.grey,
            labelText: 'Password',
            labelStyle: TextStyle(color: Colors.grey),
          controller: controller,
          obscureText: true,
          autovalidate: true,
          autocorrect: false,
          textInputAction: TextInputAction.done,
          keyboardType: TextInputType.text,
          validator: (String value) {
            if (state.errors.containsKey('password'))
              return state.errors['password'];
            return null;

Here is the authentication_model.dart file:

class AuthenticationModel {

  @Required(error: 'Email is required')
  String email;

  @Required(error: 'Password is required')
      minLength: 8,
      maxLength: 16,
      includesAlphabeticalCharacters: true,
      includesUppercaseCharacters: true,
      includesNumericalCharacters: true,
      includesSpecialCharacters: true,
      error: 'Invalid password')
  String password;

Here is the authentication_form_bloc.dart:

class AuthenticationFormBloc
    extends Bloc<AuthenticationFormEvent, AuthenticationFormState> {
  AuthenticationFormState get initialState => AuthenticationFormState.initial();

  Stream<AuthenticationFormState> mapEventToState(
    AuthenticationFormEvent event,
  ) async* {
    if (event is PasswordChangedEvent)
      yield* _onPasswordChanged(event.password);

  Stream<AuthenticationFormState> _onPasswordChanged(String password) async* {
    yield currentState.copyWith(password: password);

Here is the authentication_form_event.dart file:

abstract class AuthenticationFormEvent extends Equatable {
  AuthenticationFormEvent([List props = const []]) : super(props);

class PasswordChangedEvent extends AuthenticationFormEvent {
  final String password;

  PasswordChangedEvent({@required this.password}) : super([password]);

  String toString() => 'PasswordChangedEvent { password: $password }';

Here is the authentication_form_state.dart file:

import 'dart:convert';

import 'package:easy_validation/easy_validation.dart';
import 'package:equatable/equatable.dart';
import 'package:greenworld/main.reflectable.dart';
import 'package:greenworld/models/authentication_model.dart';
import 'package:meta/meta.dart';

class AuthenticationFormState extends Equatable {
  final String email;
  final String password;
  final Map<String, ValidationError> errors = Map<String, ValidationError>();
  final bool isFormValid;

    @required this.email,
    @required this.password,
    Map<String, ValidationError> errors,
    @required this.isFormValid,
  }) : super([
        ]) {

  bool _validate(AuthenticationModel model, Map<String, ValidationError> _errors) {
    bool _isFormValid = ModelState.isValid<AuthenticationModel>(model);

    if (_isFormValid) {
      print('form is valid');
    } else {
      print('Form is not valid');
      _errors.addAll(ModelState.errors ?? Map<String, ValidationError>());

    return _isFormValid;

  factory AuthenticationFormState.initial() {
    return AuthenticationFormState(
      email: '',
      password: '',
      errors: Map<String, ValidationError>(),
      isFormValid: false,

  AuthenticationFormState copyWith({
    String email,
    String password,
    String retypePassword,
  }) {
    AuthenticationModel model = AuthenticationModel(
      email ?? this.email,
      password ?? this.password,
    Map<String, ValidationError> _errors = Map<String, ValidationError>();
    bool _isFormValid = _validate(model, _errors);

    return AuthenticationFormState(
      email: email ?? this.email,
      password: password ?? this.password,
      errors: _errors,
      isFormValid: _isFormValid,

  String toString() {
    return '''AuthenticationFormState {
      email: $email,
      password: $password,
      errors: $errors,
      isFormValid: $isFormValid,

Feature requests and bug reports #

Please file feature requests and bugs using the github issue tracker for this repository.

[0.0.1] - 2019-09-09.

First publishing of Easy Validation package.

[0.0.2] - 2019-09-20.

Fixing validators. Improving errors.

[0.0.3] - 2019-09-20.

Fixing validators. Improving errors.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  easy_validation: ^0.0.3

2. Install it

You can install packages from the command line:

with Flutter:

$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:easy_validation/easy_validation.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Dec 13, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.0
  • pana: 0.13.1+4
  • Flutter: 1.12.13+hotfix.4

Health suggestions

Fix lib/annotations/validators/membership_password.dart. (-0.50 points)

Analysis of lib/annotations/validators/membership_password.dart reported 1 hint:

line 1 col 8: Unused import: 'dart:math'.

Format lib/model_state.dart.

Run flutter format to format lib/model_state.dart.

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (dartdoc).

Maintain an example. (-10 points)

Create a short demo in the example/ directory to show how to use this package.

Common filename patterns include main.dart, example.dart, and easy_validation.dart. Packages with multiple examples should provide example/README.md.

For more information see the pub package layout conventions.

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

The package description is too short. (-9 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
build_runner ^1.6.7 1.7.2
dartdoc ^0.28.5 0.28.8 0.29.2
flutter 0.0.0
reflectable ^2.1.0 2.2.0
Transitive dependencies
analyzer 0.38.5 0.39.2+1
args 1.5.2
async 2.4.0
build 1.2.2
build_config 0.4.1+1
build_daemon 2.1.2
build_resolvers 1.2.1 1.3.0
build_runner_core 4.3.0
built_collection 4.3.0
built_value 7.0.0
charcode 1.1.2
checked_yaml 1.0.2
code_builder 3.2.1
collection 1.14.11 1.14.12
convert 2.1.1
crypto 2.1.4
csslib 0.16.1
dart_style 1.3.3
file 5.1.0
fixnum 0.10.11
front_end 0.1.27 0.1.29
glob 1.2.0
graphs 0.2.0
html 0.14.0+3
http 0.12.0+2
http_multi_server 2.1.0
http_parser 3.1.3
intl 0.16.0
io 0.3.3
js 0.6.1+1
json_annotation 3.0.0
kernel 0.3.27 0.3.29
logging 0.11.3+2
markdown 2.1.3
matcher 0.12.6
meta 1.1.8
mime 0.9.6+3
mustache 1.1.1
node_interop 1.0.3
node_io 1.0.1+2
package_config 1.1.0
package_resolver 1.0.10
path 1.6.4
pedantic 1.9.0
platform 2.2.1
pool 1.4.0
process 3.0.12
pub_semver 1.4.2
pubspec_parse 0.1.5
quiver 2.1.2+1
resource 2.1.6
shelf 0.7.5
shelf_web_socket 0.2.3
sky_engine 0.0.99
source_span 1.5.5
stack_trace 1.9.3
stream_channel 2.0.0
stream_transform 0.0.20 1.1.0
string_scanner 1.0.5
term_glyph 1.1.0
timing 0.1.1+2
typed_data 1.1.6
vector_math 2.0.8
watcher 0.9.7+13
web_socket_channel 1.1.0
yaml 2.2.0
Dev dependencies