Skip to content

AlexanderFarkas/trigger

Repository files navigation

Trigger logo

Trigger

Boilerplate-free form validation library.

Preface

  • Minimalistic.
  • Perfectly fits flutter's form handling system.
  • Your teammates just need to explore a couple of simple concepts.

Use case: We want to validate that email doesn't exist in our database. If it does, display error.

class SignUpFormState extends ChangeNotifier with ValidationMixin {
  FieldBoolTrigger _email;

  SignUpFormState([
    this._emailAlreadyExistsTg = const FieldBoolTrigger.disabled()
  ]);

  String? validateEmail(String? email) {
    return validate(email)
      .isValidatedByBool(_emailAlreadyExistsTg)
      .isEmail()();
  }

  Future<void> submit() {
    await Future.delayed(Duration(seconds: 1)); // access the database

    // suppose, that we checked email presence, and there is user with this email already
    _emailAlreadyExistsTg = FieldBoolTrigger();
    notifyListeners();
  }
}

Somewhere in Flutter code:

final signUpFormState = SignUpFormState();

void initState() {
  super.initState();
  signUpFormState.addListener(() => setState(() {}));
}

Widget build(BuildContext context) => Column(
  children: [
    TextFormField(
      validator: signUpFormState.validateEmail,
    ),
    OutlinedButton(onPressed: signUpFormState.submit),
  ]
);

Trigger ships several different types of triggers. The most used ones - FieldTrigger and FieldBoolTrigger

When trigger.isDisabled == true, it always validates value it receives.

Example:

class State with ValidationMixin {
  FieldBoolTrigger emailAlreadyExists = const FieldBoolTrigger.disabled();

  String? validateEmail(String? email) {
    return validate(email) // comes from ValidationMixin
      .isValidatedByBool(emailAlreadyExists, error: "Already exists")()
  }
}
final state = State();
state.validateEmail("example@mail.com")
>>> null // always, because emailAlreadyExists is disabled

If we reassign emailAlreadyExists somewhere like this emailAlreadyExists = FieldBoolTrigger();

then:

final state = State();
state.validateEmail("example@mail.com")
>>> "Already exists" // Because we 'triggered' emailAlreadyExists and transitioned it to 'enabled' state.

If we validate another value within same state, it will be considered valid

state.validateEmail("anotherexample@mail.com")
>>> null // Trigger only invalidates the first value it receives after becoming enabled

Difference between *BoolTrigger and *Trigger

*BoolTrigger is a special case of Trigger.

Let's compare FieldBoolTrigger and FieldTrigger.

Instantiation

FieldBoolTrigger:

FieldBoolTrigger enabledTrigger = FieldBoolTrigger();
FieldBoolTrigger disabledTrigger = FieldBoolTrigger.disabled();

FieldTrigger:

FieldTrigger<String> enabledTrigger = FieldTrigger("API error from server");
FieldTrigger<String> disabledTrigger = FieldTrigger.disabled();

Validation

FieldBoolTrigger:

class State with ValidationMixin {
  FieldBoolTrigger enabledTrigger = FieldBoolTrigger();

  String? validateEmail(String? email) {
    return validate(email).isValidatedByBool(
      enabledTrigger,
      error: "Not validated",
    )();
  }
}

FieldTrigger:

class State with ValidationMixin {
  FieldTrigger<String> enabledTrigger = FieldTrigger("API error from server");

  String? validateEmail(String? email) {
    return validate(email).isValidatedBy(
      enabledTrigger,
      errorBuilder: (content) => "Not validated, error: $content",
    )();
  }
}

Actually the FieldBoolTrigger behavior can be achieved with FieldTrigger<bool>, but in this case you have to always provide true to enabled constructor

FieldTrigger<bool> trigger = FieldTrigger(true);

The whole work was inspired by event concept in async_redux, created by Marcelo Glasberg.

About

Boilerplate-free form validation library

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages