Revalidation lets you write your forms as stateless function components, taking care of managing the local form state as well as the validation. Revalidation also works with classes and will support other React like libraries Preact or Inferno in the future.
Install revalidation via npm or yarn.
npm install --save revalidation
Form handling sounds trivial sometimes, but let’s just take a second to think about what is involved in the process. We need to define form fields, we need to validate the fields, we also might need to display errors according to the fact if the input validates, furthermore we need to figure out if the validation is instant or only after clicking on a submit button and so on and so forth.
Revalidation takes care of running your predicate functions against defined field inputs, by separating the validation from the input. For example we would like to define a number of validation rules for two inputs, name and random.
const validationRules = {
name: [
[ isGreaterThan(5),
`Minimum Name length of 6 is required.`
],
],
random: [
[ isGreaterThan(7), 'Minimum Random length of 8 is required.' ],
[ hasCapitalLetter, 'Random should contain at least one uppercase letter.' ],
]
}
And imagine this is our input data.
const inputData = { name 'abcdef', random: 'z'}
We would like to have a result that displays any possible errors.
Calling validate validate({inputData, validationRules)
should return
{name: true,
random: [
'Minimum Random length of 8 is required.',
'Random should contain at least one uppercase letter.'
]}
Revalidate does exactly that, by defining an initial state and the validation rules it takes care of updating and validating any React Form Component.
We might have a stateless function component that receives a prop form, which include the needed field values.
import React, {Component} from 'react'
const Form = ({ form, onSubmit }) =>
(
<div className='form'>
<div className='formGroup'>
<label>Name</label>
<input
type='text'
value={form.name}
/>
</div>
<div className='formGroup'>
<label>Random</label>
<input
type='text'
value={form.random}
/>
</div>
<button onClick={() => onSubmit(form)}>Submit</button>
</div>
)
Next we might have a defined set of rules that we need to validate for given input values.
const validationRules = {
name: [
[isNotEmpty, 'Name should not be empty.']
],
random: [
[isLengthGreaterThan(7), 'Minimum Random length of 8 is required.'],
[hasCapitalLetter, 'Random should contain at least one uppercase letter.'],
]
}
Further more we know about the inital form state, which could be empty field values.
const initialState = {password: '', random: ''}
Now that we have everything in place, we import Revalidation.
import Revalidation from 'revalidation'
Revalidation needs the initial state, the validation rules, an error component and an options object as well as the Form component itself. The error component is simply telling Revalidation how to render the error messages. For example we only want to display one error at a time.
const ErrorComponent = ({errorMsgs}) => <div className='error'>{head(errorMsgs)}</div>
Revalidate will only render the error component when a field is invalid and the errorMsg prop is always an array. So in this case we want to access and render the first error message.
The options object currently supports two options: validateSingle and instantValidation.
- validateSingle: Is useful if when we only want to validate one field a time. (default: false)
- instantValidation: Set to true if new prop form values should be validated instantly. (default: false)
const option1 = {validateSingle: false} // validate all fields as soon as the first field changes f.e.
const option2 = {validateSingle: true} // validate per changed values.
const option3 = {instantValidation: false} // ignore validating any passed in props updates, f.e. only validating on submit click.
const option4 = {instantValidation: true} // validate as soon as passed in props have been updated.
Finally we enhance the Form component.
const enhanced = Revalidation(
initialState,
validationRules,
ErrorComponent,
{validateSingle: false}
)
export default enhanced(Form)
This enables us to rewrite our Form component, which accepts a reValidation prop now.
const getValue = e => e.target.value
const Form = ({ reValidation : {form, validate, valid, errors = {}, validateAll}, onSubmit }) =>
(
<div className='form'>
<div className='formGroup'>
<label>Name</label>
<input
type='text'
value={form.name}
onChange={e => validate('name', getValue(e))}
/>
{ errors.name }
</div>
<div className='formGroup'>
<label>Random</label>
<input
type='text'
value={form.random}
onChange={e => (validate('random', getValue(e))}
/>
{ errors.random }
</div>
<button onClick={() => validateAll(onSubmit)}>Submit</button>
</div>
)
reValidtion returns an object containing:
- form: form values
- validate: validation function expecting form name and value, f.e.
validate('name', 'foo')
- valid: caclulated validation state, f.e. initially disabling the submit button when a form is rendered.
- errors: the errors object either containing nothing or a error component for every defined form field.
- validateAll: validate all fields at once, also accepts a callback function that will be called incase of a valid state.
Where and how to display the errors and when and how to validate is responsibilty of the form not Revalidation. Another aspect is that the form props can als be provided when rendering the enhanced Form component.
<Form
onSubmit={this.onSubmit}
form={{name: 'foobar', random: ''}}
/>
Either define an initial state or use form props to define an actual form state. Revalidation will check for props first and then fallback to the initial state when none is found.
Also check the example for more detailed insight into how to build more advanced forms, f.e. validating dependent fields.
Clone the repository go to the examples folder and run the following commands:
yarn install
npm start.
Check the live demo
For a deeper understanding of the underlying ideas and concepts:
Form Validation As A Higher Order Component Pt.1
Form Validation As A Higher Order Component Pt.2
Written by A.Sharif
Original idea and support by Stefan Oestreicher
Revalidation is under development. The underlying validation library will be extracted into a standalone package in the near future.
MIT