DEV Community

Marco Pestrin
Marco Pestrin

Posted on • Edited on

6 4

Partial and complete validation of the form with Joi on React

Recently I started using Joi to validate forms on my React application.

In this code snippet I’ll show you how to do a partial and a full validation
The partial one when I’m typing, while the full validation when I click on the submit button.

Below here the syntax of the schema:

import Joi from 'joi';
import parsePhoneNumber from 'libphonenumber-js';

export default Joi.object().keys({
    'name': Joi.object({
        'text': Joi.string().required(),
        'voice': Joi.string().allow("")
    }).required(),
    'surname': Joi.object({
        'text': Joi.string().required(),
        'voice': Joi.string().allow("")
    }).required(),
    'phoneNumber': Joi.string().custom((phoneNumber, helper) => {
        const res = parsePhoneNumber(phoneNumber, 'IT');
        if (res !=== undefined && res.isValid()){
            return phoneNumber;
        }
        return helper.error('phoneNumber.invalid');
    }).required()
});
Enter fullscreen mode Exit fullscreen mode

Now I necessarily split the schema into more parts because I had to export different models from the file.
To make it more readable, the code becomes like this:

import Joi from 'joi';
import parsePhoneNumber from 'libphonenumber-js';

const isValidPhoneNumber = (phoneNumber, helper) => {
    const res = parsePhoneNumber(phoneNumber, 'IT');
    if (res !== undefined && res.isValid()){
        return phoneNumber;
    }
    return helper.error('phoneNumber.invalid');
};

const voiceSchema = Joi.object({
    'text': Joi.string().required(),
    'voice': Joi.string().allow("")
});

export const phoneNumberSchema = Joi.string().custom(isValidPhoneNumber).required();
export const nameSchema = voiceSchema.required();
export const surnameSchema = voiceSchema.required();

export default Joi.object().keys({
    'name': nameSchema,
    'surname': surnameSchema,
    'phoneNumber':phoneNumberSchema
});
Enter fullscreen mode Exit fullscreen mode

In the frontend it will look like this:

import React, { useState } from 'react';
import schema, { phoneNumberSchema, nameSchema, surnameSchema } from './schema2';

export const MyComponent = () => {

    const [ errors, setErrors ] = useState([]);

    function validationField(schema, value, field) {
        const err = JSON.parse(JSON.stringify(errors));
        const res = schema.validate(value);
        let errorsList = {};
        if (res.error) {
            res.error.details.forEach((error) => {
                errorsList[field] = error.message;
            });
            setErrors({
                ...errors,
                ...errorsList
            });
        } else {
            delete err[field];
            setErrors(err);
        }
    }

    function validationPaylod(payload) {
        const res = schema.validate(payload);
        if (res.error){
            // ko!
        } else {
            // ok!
        }
    }

    function handleChange(field, text, voice) {
        const payload = { 
            text,
            voice
        };
        switch (field) {
            case 'name':
                validationField(nameSchema, payload, 'name');
                break;
            case 'surname':
                validationField(surnameSchema, payload, 'surname');
                break;
            case 'phoneNumber':
                validationField(phoneNumberSchema, text, 'phoneNumber');
                break;
        }
    }

    return (<>{/* RENDER INSIDE HERE !!!! */}</>)
};
Enter fullscreen mode Exit fullscreen mode

In this case the handleChange function (with the three required parameters) will be called at the onChange event of the form and at the end we will call the validationPayload function.

Into my Errors state I have an object with all errors divided for keys.

Enjoy mates!

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay