Validation
The Form
component takes a validator
as a prop, this is an object that must
contain a validate
function and an optional validateAttribute
function.
The validate
function will take the form data and return an ErrorBag
populated with a list of errors this form data has. The validateAttribute
function will take an attribute and the form data and must return an array of
error messages corresponding to the attribute.
React Form comes with a built in validator that will handle most of the heavy lifting for you.
const validator = createValidator({username: [({ title }) => {if (!title || title.length === 0) {return "Title is required";}},],password: [({ password }) => {if (!password || password.length === 0) {return "Password is required";}},({ password }) => {if (password && password.length < 3) {return "Password must have more than 3 characters";}},],});
Each key is an attribute notation that will correspond to an attribute in formState. Each value is an array of functions that will take form state and return an error message if the validation fails. If an empty string or undefined is returned, that validation check is considered successful.
The validator supports nested attribute validation with JSON Path style deep
scan. To define a nested validator you add the attribute with a ..
for
example to validate a users first name you can use users..firstname
For these types of rules, you can use the validation options you get passed
into a validation function. For more info on validation options you can see the
ValidationOptions
type in
validator.ts
const validator = createValidator({'users..firstname': [(_, { value, path, attribute }) => {if (!value || value.length === 0) {return "Title is required";}},],});
Validation objects can also be cloned, so you can add extra rules. This can be used to add extra validation that will only run on the server. On the client validator you will get all the validation rules that can be run in the browser, in the server validator you get all the rules from the client and extra ones that can access databases to-do extra checks.
const clientValidator = createValidator({email: [(({ email }) => isEmpty(email) && "Email cannot be blank")]})const serverValidator = clientValidator.clone().addRule('email', ({ email }) => isInDb(email) && "Email must be unique")
Async validators are also allowed if you need to await http or database calls when building validators.
const validator = createValidator({url: [async ({ url }) => {const result = await fetch(url, { method: "HEAD" });if (result.status >= 400) {return `${url} is not accessible`;}},],});