Typescript Form Validation In React and React Framework Material UI

Multiple validations on TextFields or Select fields? Simply use this validation form coded in React, the framework Material UI and Typescript. It works with plain textfields and without the HTML form element.

Tuedo#010

 by  tuedodev

22
Feb 2022
 0

You would like to implement your own validation, with your own error texts and Formic would be too over-engineered for your task? This simple React component implements this using custom hooks and tuned by the React framework Material UI.

With this simple React validation form, consisting of Material UI TextField components (extendable with the select prop to create a select component), several regex validations can be pipelined and the corresponding error messages can be displayed.

How the validation works

The React component works in such a way that the submit button is only active when no more errors exist inside the TextFields and possible required props are taken into account. If so, the component function submit is called (in this example the input object will be just displayed).

function submit(){
    let str = ALERT;
    str += Object.keys(obj).map(item=>obj[item].value).join('\n');
    alert(str);
}

Hence, own validations can be created and it is not necessary to resort to the HTML5 validation of the form element (the form HTML element is not used at all).

Material UI TextField validated with React Custom Hook

Each input component inside the form uses the custom hook useFormValidation for validation, which checks the input after each onChange event and outputs the corresponding error message when necessary.

import React, { useState } from "react"
import { NO_ERROR, FIELD_REQUIRED } from '../constants'

type InitType = {
    [key: string]: any
}

type FormValidationItemType = {
            regex: RegExp,
            errorMsg: string
}

type FormValidationType = {
    [key: string]: {
        value: string,
        label: string,
        required?: boolean,
        valid: boolean,
        validation: Array,
        select?: Array 
    }
}

export const useFormValidation = (props: FormValidationType) => {
    const {initValue, initValid, initHelperText} = getInitValues();
    const [value, setValue] = useState(initValue);
    const [isValid, setIsValid] = useState(initValid);
    const [helperText, setHelperText] = useState(initHelperText);

    function getInitValues(){
        let initValue: InitType = {};
        let initValid: InitType = {};
        let initHelperText: InitType = {};
        for (const [key, value] of Object.entries(props)) {
            initValue[key] = value.value;
            initValid[key] = value.valid;
            initHelperText[key] = NO_ERROR;
        }
        return {initValue, initValid, initHelperText};
    }

    let obj: InitType = {};

    for (const [key, val] of Object.entries(props)) {
        obj[key] = {
            value: value[key],
            isValid: isValid[key],
            required: val.required,
            bind: {
                value: value![key],
                onChange: (event: React.ChangeEvent) => {
                    setValue(prev => {
                        return {...prev, [key]: event.target.value};
                    });
                    const required = event.target.required;
                    let validationArr = required ? [FIELD_REQUIRED]: [];
                    validationArr = validationArr.concat(val.validation);
                    let errArr = validationArr.map(v => {
                        return event.target.value.search(v.regex);
                    });
                    let validationState = errArr.filter(i => i < 0).length === 0 ? true : false;
                    let index = errArr.findIndex(e => e === -1 );
                    let errorMsg = validationState ? NO_ERROR : validationArr[index].errorMsg;
                    setHelperText(prev => {
                        return {...prev, [key]: errorMsg};
                    });
                    setIsValid(prev => {
                        return {...prev, [key]: validationState};
                    });
                },
                helperText: isValid[key] ? NO_ERROR : helperText![key],
                error: !isValid[key],
            },
        }
    }
    obj.resetValue = () => {
        const {initValue, initValid, initHelperText} = getInitValues();
        setValue(initValue);
        setIsValid(initValid);
        setHelperText(initHelperText);
    }
    return obj;
}

If the required prop of the Material UI TextField is set or true, the individual validation is extended so that the TextField is only valid if an input has been made.

This React validation component can be easily enhanced with further input components such as Radio buttons and Checkboxes.

Github Repository of the Code

CodePen Live-Demo

This post has not been commented on yet.

Add a comment