Skip to content
This repository has been archived by the owner on Feb 13, 2021. It is now read-only.
Prescott Breeden edited this page Nov 19, 2020 · 39 revisions

Preface

{...}

{...} represents unimportant code or unspecified file locations which have been removed from the example to reduce potential confusion.

State

"State" (as an argument) is short-hand for an object that contains all of the form or data values to be tested against the defined schema.


More about "state" as an argument

When supplying a validation function with an argument for state, it is assumed that state is the object containing the property of the validation (e.g. "state" for a Person validation will assume that the argument is a Person object and the keys of that object reflect the keys of the validation schema). This is an assumption which can be broken, however it will result in validateAll not behaving as expected. If validation functions break away from the pattern of (property, objectWithProperty) => bool, or if the state arguments need to be unrelated schemas, then group validations can be more carefully handled with validateCustom.


Validation

JavaScript class that receives the validation schema as its constructor argument. Schemas are represented by a property name and an array of validation properties containing an error message and a validation function.

Validation will return an object that contains:

Example:

import { Validation } from 'de-formed-validations';

export const PersonValidation = () => new Validation<Person>({
  name: [
    {
      errorMessage: 'Name is required.',
      validation: (val: string) => val.length > 0,
    },    
    {
      errorMessage: 'Must only contain letters.',
      validation: (val: string) => /^[a-zA-Z]+$/.test(val);,
    },
  ],
  age: [
    {
      errorMessage: 'Cannot be boomer.',
      validation: (age: number) => val < 60,
    },   
  ],
  pets: [
    {
      errorMessage: 'Must have at least 1 pet.',
      validation: (val: any[]) => val.length > 0,
    },   
  ],
});

useValidation

React hook that receives the validation schema as its argument. Schemas are represented by a property name and an array of validation properties containing an error message and a validation function.

Validation will return an object that contains:

Example:

import { useValidation } from 'de-formed-validations';

export const PersonValidation = () => useValidation<Person>({
  name: [
    {
      errorMessage: 'Name is required.',
      validation: (val: string) => val.length > 0,
    },
    {
      errorMessage: 'Must only contain letters.',
      validation: (val: string) => /^[a-zA-Z]+$/.test(val);,
    },
  ],
  age: [
    {
      errorMessage: 'Cannot be boomer.',
      validation: (age: number) => val < 60,
    },   
  ],
  pets: [
    {
      errorMessage: 'Must have at least 1 pet.',
      validation: (val: any[]) => val.length > 0,
    },   
  ],
});

getError

Get the current error stored for a property on the validationState. If the property does not exist on the validation schema or there are no current errors for the property, getError will return an empty string.

Example:

import { PersonValidation } from '...';
const { validate } = new PersonValidation();

validate('age', 70);
const error = getError('age');
// error --> 'Cannot be a boomer.'

getFieldValid

Get the current valid state stored for a property on the validationState. If the property does not exist on the validation schema, getFieldValid will return true by default.

Example:

import { PersonValidation } from '...';
const { getFieldValid, validate } = new PersonValidation();

validate('age', 70);
const valid = getFieldValid('age');
// valid --> false

isValid

A boolean that will be true if there are no errors in the validationState.

Example:

const { isValid } = PersonValidation();
// isValid --> true

resetValidationState

A function that will reset the validation state to its initial truthy state. Useful for situations where either an already rendered form may dynamically receive new data on an event and the previous validation state needs to be cleared or if a form needs to be cleared of all data.

Example:

import { PersonValidation } from '...';
const { resetValidationState } = new PersonValidation();
resetValidationState();

validate

Executes a validation function on a value and updates the validationState. Returns true if all validations pass. Returns false if any validations fail. Validate is the function behind the scenes that generates all updates to the validationState. Validate can receive an optional 3rd parameter of state if the validation function in the validation schema needs it.

Example:

import { PersonValidation } from '...';
const { validate } = new PersonValidation();

state.name = 'Bob Ross';
const validation = validate('name', state.name);
// validation --> boolean

Or...

state.name = 'Bob Ross';
const validation = validate('name', state.name, state);
// state is optional parameter

validateAll

Runs validate on each property of an object and updates the validationState. Returns true if all validations pass.

Example:

const validation = validateAll(state);
// validation --> boolean

validateCustom

Takes an array of custom arguments to call validate with and then updates the validationState. Returns true if all validations pass. Use cases for validateCustom are not common but have arisen during highly complex business logic validations as well as during multi-state back-end validations for example during a register or login request where you might want to validate the data differently in the context of an existing vs non-existing user while still maintaining a single validation schema.

Example 1:

// server registration validation
import {Validation} from 'de-formed-validations';
import { User } from '...';
import { validEmail } from '...';

export const registerValidations = () =>
  new Validation<User>({
    username: [
      {
        errorMessage: 'Username must be longer than 2 characters.',
        validation: (username: string, _) => {
          return username.trim().length > 2;
        },
      },
      {
        errorMessage: 'Username is already taken',
        validation: (_, dbData: User | undefined) => {
          return dbData === undefined;
        },
      },
    ],
    email: [
      {
        errorMessage: 'Must be a valid email',
        validation: (email: string, _) => {
          return validEmail(email.trim());
        },
      },
      {
        errorMessage: 'Email is already registered',
        validation: (_, dbData: User | undefined) => {
          return dbData === undefined;
        },
      },
    ],
    password: [
      {
        errorMessage: 'Password cannot be password',
        validation: (password: string, _) => {
          return password.trim() !== 'password';
        },
      },
    ],
  });
// server controller logic
const { username, email, password } = data;

const usernameExists = await User.findOne({ username });
const emailExists = await User.findOne({ email });

const { validateCustom } = registerValidations();
const valid = validateCustom([
  { key: 'username', value: username, state: usernameExists },
  { key: 'email', value: email, state: emailExists },
  { key: 'password', value: password, state: null },
]);

if (!valid) {
  // handle errors
}

validateIfTrue

Updates the validationState if the validation succeeds. Returns the boolean result of the validation function. End-user research has shown that it is a best practice to avoid showing errors while a user is in the process of entering data in an input. In these patterns, onBlur or submission events will typically drive error generation, and validateIfTrue will listen for when a user reaches a valid state so the error is immediately removed.

// Name is required example

state.name = '';
const validation = validateIfTrue('name', state.name);
// validation --> false
// validationState --> no change

state.name = 'Chuck Norris';
const validation = validateIfTrue('name', state.name);
// validation --> true
// validationState --> updated

validateOnBlur

A function that takes state as an argument and returns a new function which takes an event as an argument. When the function is invoked, it will call validate on the property matching the name of the event.

This function is syntactic sugar and is identical to calling validate on a blur event.

Example:

const handleBlur = handleOnBlur(state);
<input name="name" onBlur={handleBlur} {...} />

validateOnChange

A function that takes as its arguments 1) a function which receives an onChange event, 2) state, and returns a new function which takes an onChange event as an argument and calls validateIfTrue on the property matching the name of the event.

This function is syntactic sugar and is identical to calling validateIfTrue from inside the onChange function.

Example:

const onChange = (event: any) => { ... };
const handleChange = handleOnChange(onChange, state);
<input name="name" onChange={handleChange} {...} />

validationErrors

A read-only array of strings with all current error messages in the validation state.


validationState

A read-only object that tracks the validation information defined by the schema.

interface ValidationState {
  [key: string]: {
    isValid: boolean;
    errors: string[];
  };
};