aDabOfRanch
aDabOfRanch

Reputation: 147

ReactJS Handling Form Errors With MaterialUI

When the form is submitted I want to validate two fields. Specifically I want to check if the password has at least 5 characters, and that the password and confirmPassword fields match. I went ahead and implemented state to hold these error message. However, not all errors are being displayed. Example: supposed for the password field a user entered 'hell' and for password confirmation they entered 'hello'. You would expect 2 error messages (password too short, passwords don't match) but my form only displays one error - passwords don't match.

I suspect the issue lies in the validateFields function. If I swap the order of the if-statements and enter the same input I described above then I manage to see the 'password must contain at least 5 characters' error but not the 'passwords don't match error'. In addition, when using the react dev-tools I notice in the error state only one message is being set. So I don't think I'm using setState properly, maybe spread operator is not working as I intended?

import React, {useState} from 'react'
import {Grid, TextField, RadioGroup, Radio, FormControl, FormLabel, FormControlLabel, Checkbox, Button} from '@material-ui/core'

const Registration = () => {
    const [data, setData] = useState({
        username: '',
        email: '',
        password: '',
        confirmPassword: '',
    })

    const [errors, setErrors] = useState({
        short: '',
        mismatch: '',
    })

    const handleChange = e => {
        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value
        setData({
            ...data,
            [e.target.name]: value,
        })
    }

    const validateFields = () => {
        let error = false
        if (data.password && data.password.length < 5) {
            error = true
            console.log('password was too short')
            setErrors({...errors, short: 'Password must contain at least 5 characters'})
            console.log('short set')
        }
        if (data.confirmPassword && data.confirmPassword !== data.password) {
            error = true
            setErrors({...errors, mismatch: "Passwords don't match"})
        }
        return error
    }

    const handleSubmit = e => {
        e.preventDefault()
        console.log(data)
        if (validateFields()) {
            return
        }
    }

    return (
        <Grid id='registration-form' container xs={12} direction='column'>
            <Grid item xs={12} align='center'>
                <h1>Register</h1>
            </Grid>
            <form onSubmit={handleSubmit}>
                <Grid container spacing={2} xs={12} alignItems='center' justify='center'>
                    <Grid container item xs={3} direction='column' spacing={2}>
                        <Grid item>
                            <TextField id='username' name='username' label='Username' onChange={handleChange} value={data.username} required />
                        </Grid>
                        <Grid item>
                            <TextField id='email' name='email' label='Email' onChange={handleChange} value={data.email} required type='email' />
                        </Grid>
                        <Grid item>
                            <TextField id='password' name='password' label='Password' onChange={handleChange} value={data.password} error={errors.short !== ''} helperText={errors.short} required type='password' />
                        </Grid>
                        <Grid item>
                            <TextField
                                id='confirm-password'
                                name='confirmPassword'
                                label='Confirm Password'
                                onChange={handleChange}
                                value={data.confirmPassword}
                                error={Boolean(errors?.mismatch)}
                                helperText={errors?.mismatch}
                                required
                                type='password'
                            />
                        </Grid>
                    </Grid>
                </Grid>
            </form>
            <Grid item align='center'>
                <a href='#'>Already have an account? Login</a>
            </Grid>
        </Grid>
    )
}

export default Registration

Upvotes: 4

Views: 2087

Answers (1)

Vrushali Bhosale
Vrushali Bhosale

Reputation: 98

Change your validation function by the below code. It will work.

const validateFields = () => {
    let error = false
    if (data.password && data.password.length < 5) {
        error = true
        console.log('password was too short')

        //notice updater function here
        setErrors(state=>({...state, short: 'Password must contain at least 5 characters'}))
        console.log('short set')
    }
    if (data.confirmPassword && data.confirmPassword !== data.password) {
        error = true
        setErrors(state=>({...state, mismatch: "Passwords don't match"}))
    }
    return error
}

When your state update depends on previous state values, pass a function instead of an object to set the state to ensure the call always uses the most updated version of the state. Passing an update function allows you to access the current state value inside the updater.

Upvotes: 1

Related Questions