easy_validation 0.0.3

  • Readme
  • Changelog
  • Installing
  • new70

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':

dependencies:
  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';

@easyValidation
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';

initializeReflectable();

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

if (isValid) {
  // do stuff...
} else {
  print(ModelState.errors);
}

Practice usage for Flutter with Blocs:

Here is the authentication_form.dart file:

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

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

  AuthenticationFormBloc _authenticationFormBloc;

  @override
  void initState() {
    super.initState();
    _authenticationFormBloc = BlocProvider.of<AuthenticationFormBloc>(context);
    _emailController.addListener(_onEmailChanged);
    _passwordController.addListener(_onPasswordChanged);
  }

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  @override
  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() {
    _authenticationFormBloc
        .dispatch(EmailChangedEvent(email: _emailController.text));
  }

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

Here is the email_input.dart:

class PasswordInput extends StatelessWidget {
  PasswordInput({
    @required this.controller,
  });

  final TextEditingController controller;

  @override
  Widget build(BuildContext context) {
    final AuthenticationFormBloc _authenticationFormBloc =
        BlocProvider.of<AuthenticationFormBloc>(context);

    return BlocBuilder<AuthenticationFormBloc, AuthenticationFormState>(
      bloc: _authenticationFormBloc,
      builder: (BuildContext context, AuthenticationFormState state) {
        return TextFormField(
          decoration: InputDecoration(
            icon: Icon(
              Icons.lock,
              color: Colors.grey,
            ),
            suffixIcon: IconButton(
              icon: Icon(
                Icons.info,
                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:

@easyValidator
class AuthenticationModel {
  AuthenticationModel(
    this.email,
    this.password,
  );

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

  @Required(error: 'Password is required')
  @MembershipPassword(
      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> {
  @override
  AuthenticationFormState get initialState => AuthenticationFormState.initial();

  @override
  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:

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

class PasswordChangedEvent extends AuthenticationFormEvent {
  final String password;

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

  @override
  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';

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

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

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

    if (_isFormValid) {
      print('form is valid');
      print(json.encode(model));
      _errors.clear();
    } else {
      print('Form is not valid');
      print(json.encode(model));
      _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,
    );
  }

  @override
  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:


dependencies:
  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';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
53
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
71
Overall:
Weighted score of the above. [more]
70
Learn more about scoring.

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

  • Dart: 2.5.1
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

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 suggestions

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.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
build_runner ^1.6.7 1.6.9 1.7.1
dartdoc ^0.28.5 0.28.5 0.28.7
flutter 0.0.0
reflectable ^2.1.0 2.1.0
Transitive dependencies
analyzer 0.37.1+1 0.38.5
args 1.5.2
async 2.4.0
build 1.1.6 1.2.0
build_config 0.4.1+1
build_daemon 2.1.0
build_resolvers 1.1.1
build_runner_core 3.1.1 4.1.0
built_collection 4.2.2
built_value 6.7.1
charcode 1.1.2
checked_yaml 1.0.2
code_builder 3.2.0
collection 1.14.11 1.14.12
convert 2.1.1
crypto 2.1.3
csslib 0.16.1
dart_style 1.2.10 1.3.1
file 5.1.0
fixnum 0.10.9
front_end 0.1.21+1 0.1.27
glob 1.1.7
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.21+1 0.3.27
logging 0.11.3+2
markdown 2.1.1
matcher 0.12.5
meta 1.1.7
mime 0.9.6+3
mustache 1.1.1
package_config 1.1.0
package_resolver 1.0.10
path 1.6.4
pedantic 1.8.0+1
platform 2.2.1
pool 1.4.0
process 3.0.12
pub_semver 1.4.2
pubspec_parse 0.1.5
quiver 2.0.5
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.19
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+12
web_socket_channel 1.0.15
yaml 2.2.0
Dev dependencies
flutter_test