Validation
Validation can be defined for each fields using the required
and validation
keys.
The required
key only specify if the field is required and not null in the values inserted by the form user, while the
validation
key defines some rules about the inserted value:
Validation modes
LetsForms supports 4 modes of validation:
- onSubmit (default): validation is executed only on submit
- onChange: validation is triggered at every value change of any field (can degrade performance)
- onBlur: validation is triggered every time a field looses focus (can degrade performance)
- all: all the above (can degrade performance)
Every time validation errors are found, the onError
callback is called. The payload is an object: keys are the field names
and values are objects with the field labels and the error messages:
{
"my_field": {
"label": "My field",
"name": "my_field",
"errorMessage": "This is required"
},
"my_array": {
"label": "My field",
"name": "my_field"
// "errorMessage": "Minimum length is 2"
"errorMessages": [
{
// nested errors in the nested form inside of array
"my_field_in_array": {
"label": "My field in the array",
"name": "my_field_in_array",
"errorMessage": "This is required"
}
},
// ...
]
}
}
LetsForm will validate also nested forms of arrays, in that case the key errorMessages
is an array of validation object
for each of the array items (note that an array
component can still have a key errorMessage
in case the validation fails
at the array
component, for example if minLength
is not satisifed).
The validation object
Key | Type | Description |
---|---|---|
minLength | number | Minimum length, for string fields and arrays (i.e. input-text , array ) |
maxLength | number | Maximum length, for string fields and arrays (i.e. input-text , array ) |
min | number | Minimum value, for numeric fields (i.e. input-number ) |
max | number | Minimum value, for numeric fields (i.e. input-number ) |
message | string / i18n | The message to display if validation fails |
pattern | string | A regular expression used to validate a string value, omit the / s (i.e., use [a-z0-9] and not /[a-z0-9]/ |
validate | string | JavaScript code for validation (asynch function) |
For example
{
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "my_field",
"label": "My field",
"component": "input-text",
"required" true,
"validation": {
"minLength": 5,
"maxLength": 10,
"message": "There's something wrong with this value"
}
}
]
}
I18N support
I18N is supported in the validation message
key
{
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "my_field",
"label": "My field",
"component": "input-text",
"required" true,
"validation": {
"minLength": 5,
"maxLength": 10,
"message": {
"en-US": "There's something wrong with this value",
"it-IT": "C'e' qualcosa che non va in questo valore"
}
}
}
]
}
Advanced validation
More complex validation can be implemented with some simple JavaScript using the validate
keys
{
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "my_field",
"label": "My field",
"component": "input-text",
"required" true,
"validation": {
"message": "There's something wrong with this value",
"validate": "if (value.length < 10) { return false; }"
}
}
]
}
In this simple example it just checks for the string to be at least 10 chars.
In the JavaScript code, these variables are available:
value
is the value inserted by the user for the specific fieldformValues
is a hash with all current values of the form
The JavaScript code should return
true
ornull
orundefined
or nothing if the value is to be considered invalidfalse
if the value is invalid, in that case will be shown the error message defined inmessage
or the default one- string or a i18n object if the value is not valid and a customi error should be shown
For example, in order to return a custom localized error message
{
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "my_field",
"label": "My field",
"component": "input-text",
"required" true,
"validation": {
"message": "There's something wrong with this value",
"validate": `if (value.length < 10) {
return {
'en-US': 'There\'s something wrong with this value',
'it-IT': 'C\'e\' qualcosa che non va in questo valore'
};
}`
}
}
]
}
Advanced validation with external values
Sometimes it's needed to validate forms based on dynamic values (not included in the JSON form schema). In this scenario the Form Context can be useful.
For example consider the scenario where the username
needs to be validated against an array of values of
existing usernames:
const SIGNUP_FORM = {
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "username",
"label": "Username",
"component": "input-text",
"required" true,
"validation": {
"message": "There's something wrong with this value",
"validate": `if (!value) {
return 'Missing username';
}
if (context('existingUsernames').includes(value)) {
return 'Username already taken';
}
`
}
}
]
}
In this case we're using the form context to store in existingUsernames
the existing usernames,
then context()
in Form Script to fetch the value in the JavaScript validator
// example of external variables for validation
const usernames = ['my_username', 'another_username', 'some_username'];
const MyForm = () => {
return (
<LestForm
form={SIGNUP_FORM}
context={{
existingUsernames: usernames
}}
// ...
/>
);
}
Pay attention to the context prop in <LetsForm/>
, if the value changes it causes the form re-render, the example above
is wrong since at every re-render of MyForm
a new object is passed to the context
prop which causes also a re-render
of the form. See Form Context for more info.
Advanced validation with asynchronous call
The validate function is an asinchrous function and it accepts await ...
statements. The example above can be rewritten
using an external call
const SIGNUP_FORM = {
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "username",
"label": "Username",
"component": "input-text",
"required" true,
"validation": {
"validate": `if (!value) {
return 'Missing username';
}
const result = await fetch('/my_endpoint?username=' + value);
if (result.status !== 200) {
return 'Username already taken';
}
`
}
}
]
}
The validate function can also include imports()
statements to include external EE6 modules
const SIGNUP_FORM = {
"$schema": "https://unpkg.com/lets-form/schemas/react-rsuite5/form.json",
"version": 2,
"fields": [
{
"name": "vat",
"label": "VAT",
"component": "input-text",
"required" true,
"validation": {
"validate": `if (!value) {
return 'Missing VAT';
}
const { checkVAT, italy } = await import('https://cdn.jsdelivr.net/npm/jsvat@2.5.3/+esm');
const check = checkVAT(value, [italy]);
if (!check || !check.isValid) {
return 'Invalid VAT';
}
`
}
}
]
}