1
votes

I am creating a form with React-Hook-Form. I have set useForm({mode: 'onBlur'}) to trigger validation instantly and show error message right after user onBlur an element. For input text fields, it works fine. However, it doesn't work with my <Controller /> element, which wraps an customized <Select />.

The following is my code:

import React from 'react';
import { useForm, Controller, ErrorMessage } from 'react-hook-form';
import Select from '../../components/UI/Select';

const departmentList = [
    { name: 'PLEASE SELECT', value: '' },
    { name: 'Finance', value: 'FIN' },
    { name: 'IT', value: 'IT' },
    { name: 'Business', value: 'BIZ' }
];

const Form = props => {
    const { register, handleSubmit, control, errors } = useForm({ mode: "onBlur" });

    const onSubmit = (data) => {
        console.log(data);
    }
    return (
        <form onSubmit={handleSubmit(onSubmit)} style={{backgroundColor: 'white'}}>
            <div>
                <label>First Name:</label>
                <input type="text" name='firstName' ref={register({ required: 'First name cannot be null.' })} />
                <ErrorMessage errors={errors} name='firstName' />
            </div>

            <div>
                <label>Last Name:</label>
                <input type='text' name='lastName' ref={register({ required: 'Last name cannot be null.' })} />
                <ErrorMessage errors={errors} name='lastName' />
            </div>

            <div>
                <label>Department:</label>
                <Controller
                    as={<Select options={departmentList} />}
                    control={control}
                    valueName="selected"
                    rules={{ required: 'Department cannot be null.' }}
                    name="department"
                />
                <ErrorMessage errors={errors} name='department' />
            </div>

            <input type="submit" value="Submit" />
        </form>
    );
}

export default Form;

The following is the <Select /> element:

import React from 'react';

const Select = props => {
    let optionList = null;

    if(props.options) {
        optionList = props.options.map((o, i) => <option key={i} value={o.value}>{o.name}</option>)
    }

    return (
        <select 
            className="form-control" 
            value={props.value}
            style={props.style} 
            selected={props.selected}
            onChange={props.onChange}
        >
            { optionList }
        </select>
    );
};

export default Select;

After clicking on the select, choosing the empty value, and then blur, it doesn't show the error message onBlur.

Is there any way to make the trigger validation and show error message onBlur? Do I missed anything?

1

1 Answers

2
votes

react-hook-form cannot directly direct the blur state of select component. Instead what it does is to send in the onBlur function to the component passed to controller. You have to receive the prop and add it to your custom select.

const Select = props => {
    let optionList = null;

    if(props.options) {
        optionList = props.options.map((o, i) => <option key={i} value={o.value}>{o.name}</option>)
    }

    return (
        <select 
            className="form-control" 
            value={props.selected}
            style={props.style} 
            onChange={props.onChange}
            onBlur={props.onBlur}
        >
            { optionList }
        </select>
    );
};

An HTML select by default receives it's value through the value property, so the selected does not do anything on the select. It is props.selected because you have set valueName as selected on the controller.

Stackblitz