Blueprint
Blueprint

Reputation: 442

Validating only a part of formik form with useFormik hook

I am building a multi-step form with Formik, Yup, and Material-UI. I maintain the formik state in a parent form, and the page number in a different state using useState, which dictates which child component to render. I am passing formik as props and a next/previous page function.

I want to allow moving to the next page in the child component only when the inputs in that specific page are valid. I didn't find any direct solution from reading the documantation, so created the following solution in the PageOne component.

the is considerably large and has many steps, is there maybe a finer way of reaching into formik/yup and gettting those specific values validity?

here is an example code (smaller scale than app for readabilty, but the idea is the same), parent component:

import React, { useState } from 'react';
import * as yup from 'yup';
import { useFormik } from 'formik';
import {
    Button,
    Paper
} from '@material-ui/core';
import PageOne from './components/PageOne';
import PageTwo from './components/PageTwo';

const initialValues  = {
    firstName: '',
    lastName: '',
    country: '',
    age: null,
}

const onSubmit = (values) => {
    console.log('Form Data \n', values)
}

const validationSchema = yup.object({
    firstName: yup.string().required('Required field'),
    lastName: yup.string().required('Required field'),
    country: yup.string().required('Required field'),
    age: yup.number().required('Required field'),
})

const FormParent = () => {

    const formik = useFormik({
        initialValues,
        onSubmit,
        validationSchema,
    })

    const [page, SetPage] = useState(1);

    const nextPage = () => SetPage(page + 1)

    const prevPage = () => SetPage(page - 1)

    return(
        <form>
            <Paper}>
                {page === 1 && <PageOne formik={formik} nextPage={nextPage} />}
                {page === 2 && <PageTwo formik={formik} prevPage={prevPage} />}
            </Paper>
        </form>
    )
}

export default FormParent;

and a Page component example:

import React from 'react';
import { useFormik } from 'formik';
import {
    Button,
    TextField,
    FormHelperText 
} from '@material-ui/core';

const PageOne = ({ formik, nextPage }) => {

    const pageIsValid = () => {
        if (!formik.touched.firstName && !formik.touched.firstName && !formik.touched.firstName) {
            return false;
        } else {
            return (
                !(formik.errors.lastName && formik.touched.lastName) &&
                !(formik.errors.firstName && formik.touched.firstName) &&
                !(formik.errors.age && formik.touched.age)
            )
        }
    }

    return(
        <div style={{width: '100%'}}>
            <div style={{width: '100%'}}>
                <TextField 
                    {...formik.getFieldProps('firstName')} 
                    fullWidth 
                    label="First Name" 
                    name='firstName' 
                    variant="outlined"
                    helperText={formik.errors.firstName && formik.touched.firstName && `${formik.errors.firstName}`}
                    error={formik.errors.firstName && formik.touched.firstName}
                />
                <TextField 
                    {...formik.getFieldProps('lastName')} 
                    fullWidth
                    label="Last Name" 
                    name='lastName' 
                    variant="outlined"
                    helperText={formik.errors.lastName && formik.touched.lastName && `${formik.errors.lastName}`}
                    error={formik.errors.lastName && formik.touched.lastName}
                />
                <Button disabled={!pageIsValid()} fullWidth variant='contained' color='primary' onClick={nextPage}>
                    Next Page
                </Button>
            </div>
        </div>
    )
}

export default PageOne;

Upvotes: 1

Views: 11095

Answers (1)

Halim
Halim

Reputation: 278

You can do something like:

const validationPageOne = yup.object({
 firstName: yup.string().required('Required field'),
 lastName: yup.string().required('Required field')
})
const validationPageTwo = yup.object({
 country: yup.string().required('Required field'),
 age: yup.number().required('Required field')
})
       .
       .
       .
const formik = useFormik({
    initialValues,
    onSubmit,
    page === 1 ? validationPageOne : validationPageTwo,
})

Upvotes: 3

Related Questions