Advanced topics
Validation

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:

The validation object

KeyTypeDescription
minLengthnumberMinimum length, for string fields
maxLengthnumberMaximum length, for string fields
minnumberMinimum value, for numeric fields
maxnumberMinimum value, for numeric fields
messagestring / i18nThe message to display if validation fails
patternstringA regular expression used to validate a string value, omit the /s (i.e., use [a-z0-9] and not /[a-z0-9]/
validatestringJavaScript 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 field
  • formValues is a hash with all current values of the form

The JavaScript code should return

  • true or null or undefined or nothing if the value is to be considered invalid
  • false if the value is invalid, in that case will be shown the error message defined in message 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';
        }
        `
      }
    }
  ]
}