React Hook Form FKJ

by Faisal Khan Janjua

HTML

import React, { useEffect, useState } from 'react';

const SmartForm = ( form_fields, validationSchema, onSubmit, formIdentifier ) => {
    const [formData, setFormData] = useState(form_fields); // getting field values and using in state
    const [errors, setErrors] = useState({});

    useEffect(() => {
        if (form_fields !== formData) {
            setFormData(form_fields);
        }
    }, [form_fields]);

    const extractErrors = (err) => {
        let errors = {};
        err && err.inner && err.inner.map(e => errors[e.path] = e.message);
        return errors;
    };
    
    const onChangeField = (e) => {
        const field = e.currentTarget;
        const { name, value, type, checked, tagName } = field;

        if (tagName === 'SELECT' && field.multiple) formData[name] = [...field.options].filter(o => o.selected).map(o => o.value);
        else formData[name] = value;

        if(type === 'checkbox') {
            formData[name] = checked ? 1 : '';
        }

        setFormData(prevFormData => ({
            ...prevFormData,
            [name]: formData[name]
        }));

        if((type === 'checkbox') || (field.hasAttribute('validateoninput') && field.getAttribute('validateoninput').trim().toLowerCase() === 'true')) {
            validateField(e);
        }
    };

    const validateField = async ({ currentTarget: field }) => {
        const { name } = field;
        let all_errors = {};
        try {
            await validationSchema.validate(formData, { abortEarly: false });
        } catch (err) {
            all_errors = extractErrors(err); // getting all errors at once
        }
        // mapping only current error, it is re-using same logic
        setErrors((prevErrors) => ({
            ...prevErrors,
            [name]: all_errors[name] || null,
        }))
    };

    const validateAndSubmit = async (e) => {
        e.preventDefault();
        for (const elm of e.target.elements) {
            // check if still selected value is...

React

import React, { useState } from 'react';
import * as Yup from 'yup';
import SmartForm from '../../Components/form';
import { API_URL } from '../../AppConfiguration/config';
import DoHttp from '../../Services/http';


const DemoForm = () => {
    const fields = {
        any_string: 'Faisal',
        email_address: '',
        password: '',
        confirmPassword: '',
        optionalNumber: '',
        mustNot0: '',
        startDate: '',
        endDate: '',
        country: '',
        regions: '',
        is_applicable: '',
        extra_info: '',
        checkbox: '1',
        cars: '',
        textarea: '',
        iAccept: '',
    };
    
    const [form_fields, set_form_fields] = useState(fields);

    const [applicable, set_applicable] = useState(false);

    const formIdentifier = 'my_demo_form';

    const subtractDays = (date, n) => new Date(date.setDate(date.getDate() - n));
    const addMonths = (date, n) => new Date(date.setMonth(date.getMonth() + n));
    // const addDays = (date, n) => new Date(date.setDate(date.getDate() + n));
    const dt_today = subtractDays(new Date(), 1);
    const dt_validTill = addMonths(new Date(), 3);

    const validation_rules = {
        any_string: Yup.string().required('This is required'),
        email_address: Yup.string().matches(/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/, 'Must be Valid Email address').required('Email is required'),
        password: Yup.string().min(8, 'Password must have 8 characters').max(15, 'Password must not exceed 15 characters').required('Password is required'),
        confirmPassword: Yup.string().oneOf([Yup.ref('password'), null], 'Passwords do not match'),

        optionalNumber: Yup.lazy(value => {
            if (value) return Yup.string().matches(/^[0-9]+$/, 'Not a valid number');
            else return Yup.string().notRequired();
        }),
        
        mustNot0: Yup.number().notOneOf([0], '0 is not allowed').max(99, 'can not exceed 99').typeError('Not a valid...