@stormid/validate

Client-side form validation library to support .NET validation using data-val attributes as a drop-in replacement for jQuery validate, and HTML5 attribute-based constraint validation.

Usage no npm install needed!

<script type="module">
  import stormidValidate from 'https://cdn.skypack.dev/@stormid/validate';
</script>

README

Validate

Client-side form validation library to support .NET validation using data-val attributes as a drop-in replacement for jQuery validate, and HTML5 attribute-based constraint validation.


Contents

Usage

Install the package

npm i -S @stormid/validate

Import the module

import validate from '@stormid/validate';

Initialise the module via selector string

const [ validator ] = validate('form:not([novalidate])');

Initialise with a DOM element

const element = document.querySelector('form:not([novalidate])');
const [ validator ] = boilerplate(element);

Initialise with a Node list

const elements = document.querySelectorAll('form:not([novalidate])');
const [ validator ] = validate(elements);

Initialise with an Array of elements

const elements = [].slice.call(document.querySelectorAll('form:not([novalidate])'));
const [ validator ] = validate(elements);

Validators

This library supports HTML5 attribute constraints and the data-val attributes generated by .Net Core model validation, .Net MVC DataAnnotation, or .Net Fluent validation libraries.

Multiple validators can be used on a single field. Custom validators can be added via the addMethod API.


Required

The field must have a value. Checkboxes are treated as non-nullable in required validation.

HTML5

<input name="field" id="field" required>

Data attributes

<input name="field" id="field" data-val="true" data-val-required="'field' is required">

Email

Value is matched against the regular expression

/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

which is equivalent to the browser algorithm used in the constraint validation API for type="email", and is intentionally loose due to known issues related to international domain names and the validation of e-mail addresses in HTML. Stricter or more specific validation rules can be specified with a pattern attribute (or data-val-regex).

HTML5

<input type="email" name="field" id="field">

Data attributes

<input name="field" id="field" data-val="true" data-val-email="'field' must be a valid email address">

Url

The value is matched against this regular expresion by Diego Perini

/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i

Stricter or more specific validation rules can be specified with a pattern attribute (or data-val-regex).

HTML5

<input type="url" name="field" id="field">

Data attributes

<input name="field" id="field" data-val="true" data-val-url="'field' must be a valid url">

Pattern/Regex

Value matches the supplied pattern or regular expression

HTML5

<input name="field" id="field" pattern="^http(s)?">

Data attributes

<input name="field" id="field" data-val="true" data-val-regex="'field' must start with http or https" data-val-regex-pattern="^http(s)?">

Digits

Value must contain only characters in the range 0-9

Data attributes

<input name="field" id="field" data-val="true" data-val-digits="'field' must be a number">

Number

Value is matched against the regular expresion

/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/;

Allowing positive and negative numbers, decimals, and comma separated thousands.

HTML5

<input type="number" name="field" id="field">

Data attributes

<input name="field" id="field" data-val="true" data-val-number="'field' must be a number">

Min

Value is a Number greater or equal to min

HTML5

<input type="number" name="field" id="field" min="0">

Data attributes

<input type="number" name="field" id="field" data-val="true" data-val-min="'field' must be >= 0" data-val-min-min="0">

Max

Value is a Number less than or equal to max

HTML5

<input type="number" name="field" id="field" max="100">

Data attributes

<input type="number" name="field" id="field" data-val="true" data-val-max="'field' must be <= 100" data-val-max-max="100">

Range

Value is a Number within the specified min and max

Data attributes

<input type="number" name="field" id="field" data-val="true" data-val-range="'field' must be between 0 and 100" data-val-range-min="0" data-val-range-max="100">

Length

Value is a String with a length greater than or equal to min and/or a length less than or equal to max

Data attributes

<input name="field" id="field" data-val="true" data-val-length="'field' length must be between 2 and 4" data-val-length-min="2" data-val-length-max="4">

Stringlength

Value is a String with a length less than or equal to max. Equivalent to the length/max validator, generated by .Net stringlength data notation.

Data attributes

<input name="field" id="field" data-val="true" data-val-stringlength="'field' length must be less than 4" data-val-stringlength-max="4">

Maxlength

Value is a String with a length less than or equal to max. Equivalent to the length/max validator, generated by .Net maxlength data notation.

.HTML5

<input name="field" id="field" maxlength="4">

Data attributes

<input name="field" id="field" data-val="true" data-val-maxlength="'field' length must be less than 4" data-val-maxlength-max="4">

Minlength

Value is a String with a length greater than or equal to min. Equivalent to the length/min validator, generated by .Net minlength data notation.

.HTML5

<input name="field" id="field" minlength="2">

Data attributes

<input name="field" id="field" data-val="true" data-val-minlength="'field' length must be greater than 2" data-val-minlength-min="2">

DateISO

Value is a string in a format matching the date ISO standard, (YYYY-MM-DD), matching the regular expression

/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/

Data attributes

<input name="field" id="field" data-val="true" data-val-dateISO="'field' must in the format YYYY-MM-DD">

Equalto

Value must match the value of another field (or multiple fields). The data-val-equalto-other attribute is the name of another field, or a comma-separated list of names of multiple fields.

Data attributes

<input name="password" id="password">
...
<input name="passwordConfirmation" id="passwordConfirmation" data-val="true" data-val-equalto="'password confirmation' must match 'password'" data-val-equalto-other="password">

Remote

Value is validated against via XHR against a remote resource. The resouce is defined by the data-val-remote-url attribute.

Defaults to a POST request, data-val-remote-type can be set to make GET requests.

The values of additional fields can be sent in the request by specifying a data-val-remote-additionalfields attribute, a comma separated list of field ids to be included.

Data attributes

<input name="field" id="field" data-val="true" data-val-remote="'field' must pass remote validation" data-val-remote-url="/api/validate">

Errors

Error message container

The element to contain server-side error messages generated by .Net fluent and unobtrustive validation libraries is recycled by this library, it can also be manually added to HTML when you need more control over the position and markup of the error message container. The data-valmsg-for provides the association between error message and field/field group name, the id is used by the library to associate the error with the input using aria-describedby.

<span id="field-error-message" class="field-validation-valid" data-valmsg-for="field" />

If this element is not present a span is appended to the label for the field with the className .error-message.

Error messages

.Net error messages are extracted from data-val-[validator-type] data attributes, and apply to both HTML5 and .Net validators.

Fields without data-val error messages will show the default messages for the failed validator (see options below).

Including values in error messages

To include the user input value in your error message, place a token "{{value}}" within the message string and the script will replace it at the time of validation. e.g. "{{value}} is not a valid email address" will become "test@test is not a valid email address".

If a validation group contains more than one field, the values of these will be returned as a comma seperated list within the message. For example: "{{value}} are not valid inputs" becomes "test1, test2 are not valid inputs".

Options

{
    preSubmitHook: false, //function, called on validation pass, before submit
    submit: form.submit, // function, to support async form submissions, pass your own submit function
    messages: { //default HTML5 error messages
        required() { return 'This field is required'; } ,
        email() { return 'Please enter a valid email address'; },
        pattern() { return 'The value must match the pattern'; },
        url(){ return 'Please enter a valid URL'; },
        number() { return 'Please enter a valid number'; },
        digits() { return 'Please enter only digits'; },
        maxlength(props) { return `Please enter no more than ${props.max} characters`; },
        minlength(props) { return `Please enter at least ${props.min} characters`; },
        max(props){ return `Please enter a value less than or equal to ${props.max}`; },
        min(props){ return `Please enter a value greater than or equal to ${props.min}`}
    }
}

API

validate() returns an array of instances. Each instance exposes the interface

{
    validate
    addMethod
    addGroup
    removeGroup
}

addMethod

Add a custom validation method to a group:

const [ validator ] = validate('.my-form');

validator.addMethod(
    'MyFieldName', //input/input group name/or validation group name if passing an array of fields
    (value, fields) => { //validation method
        //value is the value of the whole group of fields (grouped under the name attribute)
        return value === 'test'; //must return boolean
    },
    'Value must equal "test"', //error message on validation failure
    fields // an optional array of inputs, if this isn't present the input/groupName is used as a name (or data-group) attribute selector
);

validate

Manually trigger validation on the whole form, returns a promise:

const [ validator ] = validate('.my-form');

await validator.validate();

addGroup

Add a field or field group to the validator:

const [ validator ] = validate('.my-form');
const fieldsArray = Array.from(document.querySelector('.new-fields'))

//add by passing an array of fields
//if these fields span multiple groups they will be collected into the correct validation groups internally by the validator
validator.addGroup(fieldsArray);

removeGroup

Remove a validation group from the validator:

const [ validator ] = validate('.my-form');
const fieldsArray = Array.from(document.querySelectorAll([name=new-fields]))

//add by passing an array of fields
validator.addGroup(fieldsArray);

//remove by passing the name of a group
validator.removeGroup('new-fields');

Tests

npm t

License

MIT