1.0.7 • Published 4 years ago

react-field-validation-form v1.0.7

Weekly downloads
2
License
MIT
Repository
github
Last release
4 years ago

react-field-validation-form

Custom React Hook for managing field and form level validation using Yup with support for nested data, arrays and async values.

NPM JavaScript Style Guide

Install

npm install --save react-field-validation-form

Usage

Basic

import React, { useState } from 'react'
import { string } from 'yup'
import useFieldValidationForm from 'react-field-validation-form'
import { Button, Box, FormLabel, Input } from '@chakra-ui/core'

function Basic() {
  const [values, setValues] = useState(null)

  const {
    formData,
    errors: formErrors,
    handleChange,
    handleSubmit,
    handleValidateField
  } = useFieldValidationForm({
    initialValues: {
      email: '',
      password: ''
    },

    validationSchema: {
      email: string().required('Field Required!').email('Format invalid!'),
      password: string()
        .required('Field Required!')
        .min(3, 'Minimum of 3 characters')
    },

    callBack: (outputValues) => {
      setValues(outputValues)
    }
  })

  return (
    <Box>
      <Box height='8' />
      <form method='POST' onSubmit={handleSubmit}>
        <FormLabel htmlFor='email'>Email</FormLabel>
        <Input
          type='text'
          name='email'
          id='email'
          value={formData.email}
          onChange={handleChange}
          onInput={handleValidateField}
        />
        <div>{formErrors?.email}</div>

        <Box height='8' />
        <FormLabel htmlFor='password'>Password</FormLabel>
        <Input
          type='password'
          name='password'
          id='password'
          value={formData.password}
          onChange={handleChange}
          onInput={handleValidateField}
        />
        <div>{formErrors?.password}</div>
        <Box height='8' />

        <Button variant='solid' type='submit'>
          submit{' '}
        </Button>
      </form>

      <Box height='8' />
      <Box>Output Values: {values && JSON.stringify(values, null, 2)}</Box>
    </Box>
  )
}

export default Basic

Nested Object

import React, { useState } from 'react'
import { string } from 'yup'
import useFieldValidationForm from 'react-field-validation-form'
import { Button, Box, FormLabel, Input } from '@chakra-ui/core'

function Nested() {
  const [values, setValues] = useState(null)

  const {
    formData,
    errors: formErrors,
    handleChange,
    handleSubmit,
    handleValidateField
  } = useFieldValidationForm({
    initialValues: {
      user: {
        name: '',
        email: ''
      }
    },

    validationSchema: {
      user: {
        name: string()
          .required('Field Required!')
          .min(3, 'Minimum of 3 characters'),
        email: string().required('Field Required!').email('Format invalid!')
      }
    },

    callBack: (outputValues) => {
      setValues(outputValues)
    }
  })

  return (
    <Box>
      <Box height='8' />
      <form method='POST' onSubmit={handleSubmit}>
        <FormLabel htmlFor='name'>Name</FormLabel>
        <Input
          type='name'
          name='user.name'
          id='name'
          value={formData.user.name}
          onChange={handleChange}
          onInput={handleValidateField}
        />

        <div>{formErrors?.user?.name}</div>
        <Box height='8' />

        <FormLabel htmlFor='email'>Email</FormLabel>
        <Input
          type='text'
          name='user.email'
          id='email'
          value={formData.user.email}
          onChange={handleChange}
          onInput={handleValidateField}
        />
        <div>{formErrors?.user?.email}</div>

        <Box height='8' />
        <Button variant='solid' type='submit'>
          submit{' '}
        </Button>
      </form>

      <Box height='8' />
      <Box>Output Values: {values && JSON.stringify(values, null, 2)}</Box>
    </Box>
  )
}

export default Nested

With Array

import React, { useState } from 'react'
import { string } from 'yup'
import useFieldValidationForm from 'react-field-validation-form'
import {
  Button,
  Box,
  FormLabel,
  Input,
  IconButton,
  Flex
} from '@chakra-ui/core'
import { generate } from 'shortid'

function WithArray() {
  const [values, setValues] = useState(null)

  const {
    formData,
    errors: formErrors,
    handleChange,
    handleSubmit,
    handleValidateField,
    handleArrayOnChange,
    handleValidateArrayField,
    handleArrayRemoveField,
    handleArrayPushField
  } = useFieldValidationForm({
    initialValues: {
      name: '',
      food: [{ id: '1', name: '' }]
    },

    validationSchema: {
      name: string()
        .required('Field Required!')
        .min(3, 'Minimum of 3 characters'),
      food: string()
        .required('Field Required!')
        .min(2, 'Minimum of 2 characters')
    },

    callBack: (outputValues) => {
      const food = outputValues.food.reduce(
        (acc, { id, name }) => [...acc, name],
        []
      )

      setValues({ ...outputValues, food })
    }
  })

  return (
    <Box>
      <Box height='8' />
      <form method='POST' onSubmit={handleSubmit}>
        <FormLabel htmlFor='name'>Name</FormLabel>
        <Input
          type='name'
          name='name'
          id='name'
          value={formData.name}
          onChange={handleChange}
          onInput={handleValidateField}
        />

        <div>{formErrors?.name}</div>
        <Box height='8' />

        {formData.food.map((foodType, index) => (
          <Box key={index}>
            <Flex direction='column'>
              <FormLabel htmlFor='food'>
                Preferred food No: {index + 1}
              </FormLabel>
              <Flex>
                <Input
                  type='text'
                  name='food'
                  id={foodType.id}
                  value={foodType.name}
                  onChange={(e) =>
                    handleArrayOnChange({ e, id: foodType.id, index })
                  }
                  onInput={(e) =>
                    handleValidateArrayField({ e, id: foodType.id })
                  }
                />

                {formData.food.length > 1 && (
                  <IconButton
                    aria-label='Remove Food'
                    icon='close'
                    onClick={() =>
                      handleArrayRemoveField({ key: 'food', id: foodType.id })
                    }
                    marginLeft='2'
                  />
                )}
              </Flex>
              <Box>{formErrors?.food?.[foodType.id]}</Box>
            </Flex>
            <Box height='8' />
          </Box>
        ))}

        <Button
          onClick={() =>
            handleArrayPushField({
              key: 'food',
              data: { id: generate(), name: '' }
            })
          }
        >
          Add new type of Food
        </Button>

        <Box height='8' />
        <Button variant='solid' type='submit'>
          submit{' '}
        </Button>
      </form>

      <Box height='8' />
      <Box>Output Values: {values && JSON.stringify(values, null, 2)}</Box>
    </Box>
  )
}

export default WithArray

With Async Data

import React, { useState, useEffect } from 'react'
import { string } from 'yup'
import useFieldValidationForm from 'react-field-validation-form'
import {
  Button,
  Box,
  FormLabel,
  Input,
  IconButton,
  Flex
} from '@chakra-ui/core'
import { generate } from 'shortid'

function Async() {
  const [asyncData, setAsyncData] = useState(null)
  const [isLoading, setLoading] = useState(false)
  const [values, setValues] = useState(null)

  const {
    formData,
    errors: formErrors,
    handleChange,
    handleSubmit,
    handleValidateField,
    handleArrayOnChange,
    handleValidateArrayField,
    handleArrayRemoveField,
    handleArrayPushField
  } = useFieldValidationForm({
    initialValues: {
      name: asyncData?.name ?? '',
      food: asyncData?.food.length
        ? asyncData.food.map((type, index) => ({
            id: `${index + 1}`,
            name: type
          }))
        : [{ id: '1', name: '' }]
    },

    validationSchema: {
      name: string()
        .required('Field Required!')
        .min(3, 'Minimum of 3 characters'),
      food: string()
        .required('Field Required!')
        .min(2, 'Minimum of 2 characters')
    },

    callBack: (outputValues) => {
      const food = outputValues.food.reduce(
        (acc, { id, name }) => [...acc, name],
        []
      )

      setValues({ ...outputValues, food })
    }
  })

  useEffect(() => {
    if (!asyncData) {
      setLoading(true)
      setTimeout(() => {
        setAsyncData({
          name: 'Example Name',
          food: ['fries', 'fish', 'eggs', 'tofu']
        })
        setLoading(false)
      }, 3000)
    }
  }, [asyncData])

  return (
    <Box>
      {isLoading ? (
        <Box>
          <Box height='8' />
          <Box height='8' />
          <Box>Data is Loading ...... </Box>
        </Box>
      ) : (
        <Box>
          <Box height='8' />
          <form method='POST' onSubmit={handleSubmit}>
            <FormLabel htmlFor='name'>Name</FormLabel>
            <Input
              type='name'
              name='name'
              id='name'
              value={formData.name}
              onChange={handleChange}
              onInput={handleValidateField}
            />

            <div>{formErrors?.name}</div>
            <Box height='8' />

            {formData.food.map((foodType, index) => (
              <Box key={index}>
                <Flex direction='column'>
                  <FormLabel htmlFor='food'>
                    Preferred food No: {index + 1}
                  </FormLabel>
                  <Flex>
                    <Input
                      type='text'
                      name='food'
                      id={foodType.id}
                      value={foodType.name}
                      onChange={(e) =>
                        handleArrayOnChange({ e, id: foodType.id, index })
                      }
                      onInput={(e) =>
                        handleValidateArrayField({ e, id: foodType.id })
                      }
                    />

                    {formData.food.length > 1 && (
                      <IconButton
                        aria-label='Remove Food'
                        icon='close'
                        onClick={() =>
                          handleArrayRemoveField({
                            key: 'food',
                            id: foodType.id
                          })
                        }
                        marginLeft='2'
                      />
                    )}
                  </Flex>
                  <Box>{formErrors?.food?.[foodType.id]}</Box>
                </Flex>
                <Box height='8' />
              </Box>
            ))}

            <Button
              onClick={() =>
                handleArrayPushField({
                  key: 'food',
                  data: { id: generate(), name: '' }
                })
              }
            >
              Add new type of Food
            </Button>

            <Box height='8' />
            <Button variant='solid' type='submit'>
              submit{' '}
            </Button>
          </form>

          <Box height='8' />
          <Box>
            Output Values to be sent back to server:{' '}
            {values && JSON.stringify(values, null, 2)}
          </Box>
        </Box>
      )}
    </Box>
  )
}

export default Async

Check examples folder for in depth usage.

Or See them in action

License

MIT © VictorBaba

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.2

4 years ago

1.0.3

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago