npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

form-validate.js

v1.2.2

Published

Form validation library

Downloads

32

Readme

form-validate.js

form-validate.js is a form validation library, for validating web client forms.

Introduction

form-validate.js was created to give an effective yet convenient way of validating forms (in react components and html). The library is flexible and gives you control of its effects including what errors are shown, it's styling, and flow. Scroll to the bottom of this page to see a sample react component with form validation

Requirements

  • Node and npm
  • Transpilation (conventionally with babel). create-react-app has this setup already.

Installation

npm install form-validate.js

Dependency

form-validate.js relies on validate.js for its validation rules and is shipped together with the library.

Usage

The examples in this doc are targeted for react however, the principles can be applied to forms using other tools including vanilla JS

Validating forms

  • Import form-validate.js to your js code
import FormValidate from 'form-validate.js';
  • Create a constant for an instance of FormValidate class
const validator = new FormValidate(<constraints>, <options>, <defaultValues>);

constraints is an object holding validation rules.

Note: all rules are based on validate.js rules, access the docs here to know what rules are usable and how to customize validation error messages. However, there are two rules custom and customAsync peculiar to form-validate.js

const constraint = {
  username: {
    presence: true,
  },
  password: {
    presence: true,
    length: {
      minimum: 8,
    },
  },
};

options (optional) is an object which indicates how the validate.js library handles validation errors and messages. Allowed options include fullMessages, prettify and format as seen here

defaultValues (optional) an object which indicates the values to be validated against initially, if not provided, all field values would be treated as null.

const defaultValues = {
  username: 'john',
  password: 'password',
};

custom and customAsync constriants

with the custom rule, you can have validation based on conditions you provide, simply return a string or array of messages of the error if validation fails or null if validation passes

customAsync rule makes you perform validation asynchronously in case you need to call endpoint to validate a field. To do this, return a function in which you resolve a string or array of messages if validation fails or simple call resolve() if there are no errors. You can still return plain values, in which case customAsync handles the validation as synchronous Sample custom and customAsync rules are shown below

const constraint = {
  username: {
    customAsync: (value, attributes, attributeName) => {
      if (value && value.trim() === '') return;
      return function(resolve) {
        setTimeout(() => {
          if (['joshua', 'john', 'rita'].includes(value)) {
            resolve('%{value} is taken');
          } else {
            resolve();
          }
        }, 1000);
      };
    },
  },
  unique: {
    custom: (value, attributes, attributeName) => {
      if (attributes.username === attributes.password) {
        return '^the username and password cannot be thesame';
      }
      return null;
    },
  },
};

custom constraint can be used on a control not associated with any input, provided it is the only constrain specified on the control

customAsync should return a function taking resolve as an argument, resolve should be called to indicate validation is done passing in the validation errors or without any argument if the validation passes.

  • Using the validator

Ensure the name of the input field corresponds to the object key in the validation constraints otherwise, the validator would not be associated with an input field unless it meets the condition to act as a stand-alone custom validator as stated above

<input type="text" name="username" />

If for any reason the name given to the input does not match the validation constraint key, use the validate-control or data-validate-control attribute on the input element to specify the constrian key the input is associated with.

<input type="text" name="alt-input-name" validate-control="username" />

the validation instance has a controls property validator.controls that holds the control object of each field. The control object has three important fields

  • errors - an array holding all validation errors of the field
  • touched - indicating if the control field has been interacted with
  • loading - indicating if an asynchronous validation is processing

getting a reference to a control associated with a field can be done thus

const usernameControl = validator.controls.username;

OR

const usernameControl = validator.get('username');

The errors, touched, loading and other properties and methods of the control can be access from the control object directly

const usernameErrors = validator.controls.username.errors;

const usernameTouched = validator.controls.username.touched;

The errors can be displayed in a react app as follows

<div>{usernameTouched && usernameErrors.map((error, i) => <div key={i}>{error}</div>)}</div>

the touched check should be done, otherwise errors would show up without the user interacting with the form.

  • Validating a form To validate input values in a form, add an onChange listener to the form and call the validate method in its callback passing the event and a callback function to be executed once validation is done.

    Note: Other listeners e.g. onBlur can be used to perform validation at the occurence of corresponding events.

onChange = event => {
  // Note: in a react app, the event should be the native event which can be gotten with event.nativeEvent
  // callback to be run once validation is done, the valid argument indicates if the form is valid or not, and controls is a collection of all form controls
  validator.validate(event.nativeEvent, (valid, controls) => {
	  // perform logic after validation
  });
};

A check can also be added on submit of the form, in case the user tends to bypass onchange validation. Conventionally, all errors should show up after submitting the form, this can be done by calling the validator.touchAll() function in the onsubmit handler which bypassing the touched check

onSubmit  = (event) => {
  event.preventDefault();
  if (!validator.valid()) {
    validator.touchAll();
    return;
  }
  // ...
}

Custom and Variable controls

You may need to include custom contraints later on in your code, luckily, form-validator.js provides a means of accomplishing this, you can always add controls and contraints using the validator.addControl function and remove existing ones with validator.removeControl at appropriate places in your code

validator.addControl takes in 3 arguments, controlName, rule and defaultValue validator.removeControl takes in only the controlName as an argument

validator.addControl('my-custom-control', {presence: true}, 'default-value');
...
validator.removeControl('existing-control');

Rendering Validation Errors

To display validation errors on your view, call the validator.render(callback) function. The callback is a function which takes valid and controls as arguments and its body should be the logic to render errors to the screen, Call to validator.render can be done immediately after creating the validator instance.

// the valid argument indicates if the form is valid or not, and controls is a collection of all form controls
validator.render((valid, controls) => {
  // perform logic to display errors to the users here.
  // in a react app this can be as easy as setting the state to trigger a rerender.
  // for a regular html form, certain elements can be updated to contain the validation error in controls
  this.setState({});
});

NOTE: If you used earlier version of form-validate.js, the logic to render errors should not be in the validate method callback, also the callback argument in touchAll and unTouchAll methods is deprecated.

Deprecated methods

  • validator.setReactComponent
  • validator.getValid
  • validator.isValid

See an example of full react component with form validation below

import React from 'react';
import FormValidate from 'form-validate.js';

const constraint = {
  username: {
    presence: true,
    // async validation
    customAsync: (value, attributes, attributeName) => {
      // it is possible for value to be null or undefined
      if ((value || "").trim() === "") return;

      return resolve => {
        if (value.trim() === "") {
          resolve();
          return;
        }

        setTimeout(() => {
          if (["joshua", "john", "rita"].includes(value)) {
            resolve("%{value} is taken");
          } else {
            resolve();
          }
        }, 1000);
      };
    }
  },
  password: {
    presence: true,
    length: {
      minimum: 8
    }
  },
  unique: {
    // custom validation can work on controls not associate with an input field if it is the only rule specified otherwise, it must be associated with an input field
    custom: (value, attributes, attributeName) => {
      if (attributes.username === attributes.password) {
        return "^the username and password cannot be thesame";
      }
      return null;
    }
  }
};

class Component extends React.Component {
  constructor(props) {
    super(props);

    this.validator = new FormValidate(constraint);
    this.validator.render((valid, controls) => {
      // rerender validation errors and perform actions after validation
      this.setState({});
    });
  }

  render() {
    // destructure out the controls property
    const { controls } = this.validator;

    return (
      <div>
        <form
          onChange={this.validateForm}
          onSubmit={this.onSubmit}
          autoComplete="off"
        >
          <input type="text" name="username" />
          {/* display loader if username control is loading or all username errors if field is touched */}
          {controls.username.loading ? (
            <div>checking...</div>
          ) : (
            <div>
              {controls.username.touched &&
                controls.username.errors.map((error, i) => (
                  <div key={i}>{error}</div>
                ))}
            </div>
          )}
          <input type="password" name="password" />
          {/* display first password error at all times if any exists */}
          <div>{controls.password.errors[0]}</div>
          <div>{controls.unique.touched && controls.unique.errors[0]}</div>
          {/* disable submit button based on the form valid state */}
          <button disabled={!this.validator.valid()}>Submit</button>
        </form>
      </div>
    );
  }

  validateForm = event => {
    // get nativeEvent out of the react change event.
    this.validator.validate(event.nativeEvent, (valid, controls) => {
      // perform some logic after validation
    });
  };

  onSubmit = event => {
    event.preventDefault();
    if (!this.validator.valid) {
      this.validator.touchAll();
      return;
    }
    // ...
  };
}

export default Component;