# Bruut Validate JS
This plugin can be used for all front-end validation needs. This is the successor of the Bruut-Validator plugin, which is now deprecated.
# Installation
npm install --save bruut-validate@latest
# Usage
Import BruutValidate into your project and apply BruutValidate.
TIP
Since version 2.0.0
, the default export is changed. Read about legacy imports below.
By default, the package exports a function that attaches the BruutValidate instance to all form elements in the DOM with [bruut-validate]
attributes set. You can still import the BruutValidate instance as well, via a named import.
import validate from 'bruut-validate';
validate;
// Import the BruutValidate instance (only needed if you want to do advanced stuff)
import { BruutValidate } from 'bruut-validate';
# Ready helper
Since you don't know if BruutValidate is attached directly after DOMContentLoaded, you can use the provided BruutValidateReady
helper function to wrap your functionality after the BruutValidate instance is attached to a DOM element:
// Attaches BruutValidate to all forms with [bruut-validate] tag
import validate, { BruutValidateReady } from 'bruut-validate';
validate;
// Get a specific form
const form = document.querySelector('form[bruut-validate].my-form');
BruutValidateReady(form, e => {
const instance = form['bruutValidate']; // or e.detail
instance.$events.on('form:validated', () => {
...
});
});
# Legacy import (1.x)
import BruutValidate from 'bruut-expander';
const forms = document.querySelectorAll('form[bruut-validate]') as NodeListOf<HTMLFormElement>;
for (let i = 0, len = forms.length; i < len; ++i) {
forms[i]['bruutValidate'] = new BruutValidate(forms[i]);
}
# Field setup
# Validate attribute
To add a field or checkbox / radio to the validator, make sure that there's a validate
attribute set. It should be parseable by JSON.parse()
.
validate = '{
"on" : ["keyup", "change", "blur", "input"],
"rules" : ["email", "min:2"]
"on_hidden" : false
}'
key | type | Remarks |
---|---|---|
on | Array:string | List of all events that should trigger the validation for this field. |
rules | Array:string | List of the rules that should be validated |
on_hidden | boolean *optional | If set to true, this field will validate, even if the field is hidden. |
# Checkbox / Radio
If you want to validate a checkbox / radio (or a group of checkboxes / radio's), make sure that the elements have the same name
and that one of the elements has a validate
attribute set. The plugin will validate the group on each change.
<div class="field">
<div class="control">
<input type="checkbox" name="checkboxes" id="checkbox-1" validate='{"on" : ["change"], "rules" : ["min-checked:1"]}'>
<input type="checkbox" name="checkboxes" id="checkbox-2">
</div>
</div>
# Text fields
Text fields are required to have a validate
property set, with a JSON parseable object string. You can choose one (or multiple) events to validate to and also one or multiple rules.
Make sure that the rule you use is defined as a validator function. BruutValidate will warn you about this.
<div class="field">
<div class="control">
<input type = "text" class = "input" validate = '{"on": ["change"], "rules": ["email"]}'>
</div>
</div>
# Available events
Event name | When does it fire |
---|---|
change | After radio / checkbox change and after losing focus on textareas and text fields |
keyup | After keyup in text fields and textareas |
input | After keyup, paste, edit in text fields and textareas |
# 'Lazy' validation on text fields
If you'd like to wait for validation until the user has moved focus from the field, add the class has-lazy-error
to the .field
wrapper. This class will be removed from the field as soon as the field has lost focus. The field is being validated at each event that's in the validate
string, but you can alter your CSS to show only errors and notices when the field doesn't have the class has-lazy-error
.
# Available rules
You can also add your own rules. Learn more in the 'Add your own rules' chapter.
Rule | What it does | Regex pattern |
---|---|---|
required | Checks if any value exists | |
min:(int) | Checks a minimum length | |
max:(int) | Checks a maximum length | |
characters:alpha | Checks if value only contains alpha characters. | /^[a-zA-Z]*$/ |
characters:alphaspace | Checks if value only contains alpha characters or spaces. | /^[a-zA-Z\s]*$/ |
characters:alphaspacedash | Checks if value only contains alpha characters or spaces or dashes. | /^[a-zA-Z\s-]*$/ |
characters:numeric | Checks if value only contains numeric characters. | |
min-checked:(int) | Radio / Checkbox only: Checks a minimum checked amount of items | |
max-checked:(int) | Radio / Checkbox only: Checks a maximun checked amount of items |
# Validating process
# Field
As soon as a event
(that's stored in the events
config) is fired on the form, the information in the Event
object is checked. The event.target
is checked to see if there's a validate
attribute set, or on one of it's same name
siblings if it's a checkbox or radio button.
From there, the validate
prop will be parsed and validation will begin.
- The field parent (default:
.field
) will get a check class (default:.is-checking
) during the process of validation. - Each rule you assign to the field will get its own
Promise
that will beresolved
orrejected
via the rule functions. - When all
Promises
for every rule in the field are resolved or rejected, the field errors are checked. - When the field is ok, its parent will get the success class (default:
.is-success
). When there are errors its parent will get the error class (default:.has-error
). - The check class is removed from the field parent.
- A
Custom Event
will be fired at this stage to the field (DOM element). Read more about events incallbacks
.
# Form
When a submit button with validate-check
is clicked, the validation process for the form begins:
- The default behaviour of the button will be prevented (
e.preventDefault()
). If you'd like to submit the form onvalid
, learn more in the chapter 'Submitting the form'. - The
form
will get a check class (default:.is-checking
) during this process. - The plugin will collect all fields in the
form
with avalidate
attribute set and validate all these fields (see: Validating process | field for more details). - If all
Promises
from these individual fields areresolved
orrejected
, the errors are checked - When the form is ok, it will get the success class (default:
.is-success
). When there are errors in the form it will get the error class (default:.has-error
). - A
Custom Event
will be fired at this stage to the form (DOM element). Read more about events incallbacks
.
# Callbacks
You can listen to the callbacks on the global $events
property on each instance.
TIP
Make sure that the BruutValidate
instance is attached to the element, before adding callbacks. You can use the Ready helper for this.
const instance = form['bruutValidate'];
instance.$events.on('form:validated', ({valid, errors}) => {
console.log(valid);
});
instance.$events.on('field:validated', ({field, valid, errors}) => {
console.log(valid);
});
# Form
Event | Fires when | Payload <object> |
---|---|---|
form:validated | The form is validated | { valid <boolean> , errors: <object> } |
# Field
Note : When you are listening to checkbox or radio groups, events are fired to the element that has the validate
attribute.
Event | Fires when | Payload in e.detail |
---|---|---|
field:validated | A field is validated | { field: <HTMLInputElement> , valid <boolean> , errors : false or <array> . |
# Submitting the form updated
By default the form is submitted when the form submit button is clicked and the form is valid
. You can edit this default behaviour by adding a JSON parsable object string in between the [bruut-validate]
atrribute:
<form class="my-form" bruut-validate='{"preventSubmit" : true}'>
...
</form>
A little note on submit button value
To work around the problem of missing submit button values in the $_POST
data, the clicked submit button is sent as a hidden input field with the same name
and value
as the button. If there's no button clicked (submit on 'enter') the first submit button that's found in the form is being used for tha name
and value
.
# Adding error and success messages
You can add success and error messages on a per field basis. You can add default messages for specific rules and override them with custom messages per rule in a field scope.
You can't use the keywords default
and form
, since these are reserved for the default messages and messages for the form itself.
To use messages, create a <div>
and add the attribute validate-messages
to it.
<div class="is-hidden" validate-messages>
<!-- Default RULE message -->
<span validate-default="email">Use a correct email address.</span>
<!-- Specific FIELD message -->
<span validate-error = "fieldname">Something went wrong</span>
<span validate-success = "fieldname">Yeah! All is well.</span>
<!-- Specific rule message per field (error only) -->
<span validate-error = "fieldname:email">Woops, that email address doesn't seem right.</span>
</div>
You can use html
in these messages as well.
The content will be injected in any element (inside the form) with the validate-message
attribute:
<p validate-message="fieldname"></p>
Good to know : All error messages will be chained per element, followed by a blank space:
[fieldname] [default rule] / [fieldname:rule]
Tip : If you have both a default
error message for a rule and a specific rule error message in the field, the latter takes precedence.
# Adding a message for the form
If you would like to add a message for the entire form, you can use the reserved form
as validate-error
, validate-success
and validate-message
. Don’t use this keyword for fields.
# Add your own rules
You can add your own validator logic to the plugin. Let’s make a validator for a hex
value which will validate if the value in a field is a hex value, starting with a # and 3 or 6 characters:
import BruutValidate from 'bruut-validate';
window['bruut-validate-settings'].addRule({
name: 'hex',
logic: function(rule) {
var pattern = /^#?([a-f0-9]{6}|[a-f0-9]{3})$/;
return (pattern.test(fieldValue));
return (pattern.text(this.value)) ? rule.valid() : rule.invalid();
}
});
...
TIP
Make sure that your rule is added before instantiating the bruutValidate class.
the name
is used in the rules
attribute of your field. The logic
is a function that has the field as this
and 1 additional parameter: rule
.
The rule
parameter is a object with the following information:
form
(HTMLElement) : The DOM representation of theform
.args
(Array) : Array that is filled with the extra data from your rule, if set.valid
(function) : Call this function when your validation is ready and the result isvalid
. This resolves the rulePromise
.invalid
(function) : Call this function when your validation is ready and the result isinvalid
. This rejects the rulePromise
.
Please note: You must return a
rule.valid()
orrule.invalid()
for your custom validator to work properly. If you don't return anvalid()
orinvalid()
, thePromise
won't be fullfilled.
You can use this new validator in your markup as follows:
<input type = "text" class = "input" validate = '{"on": ["change"], "rules": ["hex"]}'>
# Working with parameters in the rule
You can add some more information to a custom rule by using ':' in the rule name:
<input type = "text" class = "input" validate = '{"on": ["change"], "rules": ["hex:3:6"]}'>
This extra data is sent as args
array in the rule
parameter in your rule function. The string is split on each :
and each portion after the :
is treated as a value in the array. In this case, the args
array will be: [3,6].
# Advanced example
Let's say you'd like to create a 'match' with a other input field that is not in the validator:
<input type = "text" class = "input" id="password">
<input type = "text" class = "input" validate = '{"on" : "change", "rules" : ["match:#password"] }'>
You can write a rule
function like this:
window['bruut-validate-settings'].addRule({
name: 'match',
logic: function(rule) {
let otherfield = document.querySelector(rule.args[0]);
if (otherfield !== 'undefined') {
return (this.value.trim() === otherfield.value.trim()) ? rule.valid() : rule.invalid();
} else {
// no element found, abort!
return rule.invalid();
}
}
});
On every change
this function checks the value of the field given as parameter in your rule
and returns the validation state.