jquense / react-formal

Sophisticated HTML form management for React
http://jquense.github.io/react-formal
MIT License
526 stars 52 forks source link

Controlled component loses validation errors #113

Closed rachelleahr closed 7 years ago

rachelleahr commented 7 years ago

When using react-formal to validate fields that are updated by state, the error object keeps being reset to only contain the last field that was in focus while state was updating.

jquense commented 7 years ago

do you have some code reproducing the issue? thanks!

rachelleahr commented 7 years ago

here is my schema:

var registerSchema = yup.object().shape({
    firstName: yup.string().required('Required'),
    lastName: yup.string().required('Required'),
    gender: yup.mixed().required('Required'),
    phone: yup.string().min(10,'Invalid phone number'),
    location: yup.string().required('Required'),
    email: yup.string().required('Required').email('Invalid email'),
    password: yup.string().required('Required').min(6, 'Password is too short'),
    confirmPassword: yup.string().oneOf([this.state.newUser.password], "Passwords don't match")
});

and this is the form:

<Form onSubmit={this.submit}
      id="form"
      schema={registerSchema}
      value={this.state.newUser}
      onChange={(model)=>this.setState({newUser: model})}>

    <h3>Register Account</h3>
    <div className="container">
        <div>
            <legend>First Name
                <Form.Message for='firstName'/>
            </legend>
            <Form.Field
                placeholder="First Name"
                name='firstName'/>
        </div>
        <div className="form-inline-half">
            <legend>Last Name
                <Form.Message for='lastName'/>
            </legend>
            <Form.Field
                placeholder="Last Name"
                name='lastName'/>
        </div>
    </div>

    <div className="container">
        <div className="form-inline-half">
            <legend>Phone
                <Form.Message className='has-error' for='phone'/>
            </legend>
            <Form.Field
                placeholder="Phone"
                name='phone'
                className="form-input-margin-bottom"/>
        </div>
        <div >
            <legend>Gender
                <Form.Message for='gender'/>
            </legend>
            <Form.Field
                type='selectlist'
                data={[{ id: 1, text: "Male"}, { id: 2, text: "Female"}]}
                mapFromValue={ gender => gender.id }
                valueField='id'
                textField='text'
                name='gender'/>
        </div>
    </div>
    <div className="container">
        <legend>Location
            <Form.Message for='location'/>
        </legend>
        <Form.Field
            placeholder="Location"
            name='location'/>
    </div>
    <div className="container">
        <legend>Email
            <Form.Message for='email'/>
        </legend>
        <Form.Field
            placeholder="Email"
            name='email'/>
        <div >
            <legend>Password
                <Form.Message for='password'/>
            </legend>
            <Form.Field
                placeholder="Password"
                type='password'
                name='password'/>
        </div>
        <div>
            <legend>Confirm password
                <Form.Message for='confirmPassword'/>
            </legend>
            <Form.Field
                placeholder="Confirm Password"
                type='password'
                name='confirmPassword'/>
        </div>
    </div>

        <Form.Button type="submit">
            Register.
        </Form.Button>
</Form>
rachelleahr commented 7 years ago

Here's a screenshot of what happens. After filling in any input, that changes state and the old errors disappear. https://gyazo.com/a3ce0b66def70cefbea5f9493c4a9ff7

rachelleahr commented 7 years ago

@jquense any idea what I can do to solve this?

jquense commented 7 years ago

sorry I haven't had a chance to look more closely here.

rachelleahr commented 7 years ago

@jquense ok thanks

rachelleahr commented 7 years ago

figured out what the issue was. I had declared my schema inside the react component so that I could access state to be able to do this:

confirmPassword: yup.string().oneOf([this.state.newUser.password], "Passwords don't match")

to fix it I switched it to this:

confirmPassword: yup.mixed().test('match', 'Passwords do not match', function (confirmPassword) {
        return confirmPassword === this.parent.password
    })

and moved the schema declaration outside the react component.

thanks!