Coder Social home page Coder Social logo

stradap / revalidation Goto Github PK

View Code? Open in Web Editor NEW

This project forked from busypeoples/revalidation

0.0 2.0 0.0 1.09 MB

Higher Order Component for Validating Forms in React

Home Page: http://revalidation.oss.25th-floor.com/

License: MIT License

JavaScript 99.56% HTML 0.44%

revalidation's Introduction

Revalidation

Higher Order Component for Forms in React

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 like Preact or Inferno in the future.

Use Case

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.

Why Revalidation?

There are a number of solutions already available in React land, each with there own approach on how to tackle aforementioned problems. Revalidation is another approach on taming the problems that come with forms by only doing two things: managing the local form component state and validating against a defined set of rules. There is no real configuration and very little is hidden away from user land. This approach has pros and cons obviously. The benefit we gain, but declaring an initial state and a set of rules is that we can reuse parts of the spec and compose those specs to bigger specs. The downside is that Revalidation doesn't abstract away the form handling itself. The only configurations available are validateSingle and validateOnChange, while the first enables to define if the predicates functions are against all fields or only that one updated, the latter enables to turn dynamic validation on and off all together. This is it. Everything is up to the form implementer.

Revalidation enhances the wrapped Component by passing a revalidation prop containing a number of properties and functions to manage the state. There are no automatic field updates, validations or onsubmit actions, Revalidation doesn't how the form is implemented or how it should handlde user interactions.

Let's see an example to get a better idea on how this could work. For example we would like to define a number of validation rules for two inputs, name and random. More often that not, inside an onChange(name, value) f.e, we might start to hard code some rules and verify them against the provided input:

onChange(name, value) {
  if (name === 'lastName') {
    if (hasCapitalLetter(lastName)) {
      // then do something 
    }
  }  
  // etc...
}

This example might be exaggerated but you get the idea. Revalidation takes care of running your predicate functions against defined field inputs, enabling to decouple the actual input from the predicates.

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. Revalidate also doesn't know how your form is built or if it is even a form for that matter. This also means, a form library can be built on top Revalidation, making it a sort of meta form library.

Getting started

Install revalidation via npm or yarn.

npm install --save revalidation

Example

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 only needs the Component and returns a Higher Order Component accepting the following props:

  • initialState (Object)

  • rules (Object)

  • singleValue (Function)

  • validateOnChange: (Function)

  • asyncRules (Object)

  • updateForm (Object)

const enhancedForm = revalidation(Form)

// inside render f.e.

<EnhancedForm
  onSubmit={this.onSubmit} // pass any additional props down...
  initialState={initialState}
  rules={validationRules}
  validateSingle={true}
  validateOnChange={true}
/>

This enables us to rewrite our Form component, which accepts a revalidation prop now.

const createErrorMessage = (errorMsgs) => 
  isValid(errorMsgs) ? null : <div className='error'>{head(errorMsgs)}</div>

const getValue = e => e.target.value

const Form = ({ revalidation : {form, onChange, updateState, valid, errors = {}, validateAll}, onSubmit }) =>
  (
  <div className='form'>
    <div className='formGroup'>
      <label>Name</label>
      <input
        type='text'
        className={isValid(errors.name) ? '' : 'error'}
        value={form.name}
        onChange={compose(onChange('name'), getValue)}
      />
      <div className='errorPlaceholder'>{ createErrorMessage(errors.name) }</div>
    </div>
    <div className='formGroup'>
      <label>Random</label>
      <input
        type='text'
        className={isValid(errors.random) ? '' : 'error'}
        value={form.random}
        onChange={compose(onChange('random'), getValue)}
      />
      <div className='errorPlaceholder'>{ createErrorMessage(errors.random) }</div>
    </div>
    <button onClick={() => validateAll(onSubmit)}>Submit</button>
  </div>
  )

export default revalidation(Form)

revalidtion returns an object containing:

  • form: form values

  • onChange: a function expecting form name and value, f.e. onChange('name', 'foo')

  • updateState: a function expecting all the form values, f.e. Useful when wanting to reset the form. Depending on the setting either a validation will occur or not.

     <button onClick={() => updateState({ name: '', random: '' })}>Reset</button>
  • valid: calculated validation state, f.e. initially disabling the submit button when a form is rendered.

  • errors: the errors object containing an array for every form field.

  • validateAll: validates all fields at once, also accepts a callback function that will be called in case 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 be updated when needed.

NOTE: updateForm should be used carefully and only when needed. Make sure to reset or remove updateForm after applying the new form values.

<Form
  onSubmit={this.onSubmit}
  updateForm={{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.

Revalidation also enables to define asynchronous predicate functions via the asyncRules prop. Any predicates containing side effects have to be declared explicitly via the prop.

// isUnusedUserName is function returning a promise and sends a request to validate if the username is available f.e.

const asyncRules = {name: [[isUnusedUserName, 'Username is not available']]}
 
<EnhancedSubmitForm
  onSubmit={this.onSubmit}
  rules={validationRules}
  initialState={initialState}
  asyncRules={asyncRules}
  userNameExists={this.usernameExists}
  validateSingle={true}
  validateOnChange={true}
/>

NOTE: A sensible approach with asynchronous validation functions is useful, Revalidation will not run any effects against an input field if any synchronous predicates have failed already. Needed consideration include: when to run the side effects (dynamically or on submit) and how often to trigger an async validation (immediately on every change or debounced)

More: Revalidation also works with deep nested data structure (see the deep nested data example)

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.

Demo

Check the live demo

Further Information

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

Credits

Written by A.Sharif

Original idea and support by Stefan Oestreicher

Very special thanks to Alex Booker for providing input on the API and creating use cases.

More

Revalidation is under development.

The underlying synchronous validation is handled via Spected

Documentation

API

FAQ

License

MIT

revalidation's People

Contributors

busypeoples avatar apalm avatar bookercodes avatar

Watchers

James Cloos avatar Pablo Estrada avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.