T Nguyen
T Nguyen

Reputation: 3415

How to check if any errors exist in redux-form

I'm using React + Redux, and redux-form for form processing and validation. So far, it's been pretty easy to use and I can easily check the validation state of individual form fields using field.touched and field.error, but I can't seem to find any method or property which will tell me if there are any errors across the entire form. The way React works, any form will generate a bunch of errors as soon as it's loaded, which is why you need to use field.touched to test individual fields.

What I'm looking to do is to have some universal markup displayed if there are any errors anywhere in the form, but only once touched. So really, I was hoping there was something like form.touched and form.error. I have a design in mind for a helper function which will check all fields in a form and return a boolean but I'd prefer to avoid this if possible.

UPDATE: As per Andy_D's answer, I've updated my code to use the form-level properties dirty and invalid but dirty doesn't seem to update properly. After submitting the form and seeing individual field-level errors, the form is still showing dirty: false.

Included below is a simplified version of my code as well as the contents of the this.props object after submitting the form.

import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import { makeBooking } from '../actions/index';

class PaymentBooking extends Component {
    render() {
        const { fields: { school }, handleSubmit } = this.props;

        return (
            <form className="form-horizontal" onSubmit={handleSubmit(this.props.makeBooking)}>
                {
                    console.log(this)
                }
                {
                    this.props.dirty && this.props.invalid ? <div className="alert alert-danger" role="alert">Test error wrapper</div> : ''
                }
                <h2>Make a New Payment Booking</h2>
                <div className="panel panel-default">
                    <div className="panel-heading">Payment Information</div>
                    <div className="panel-body">
                        <div className={`form-group ${school.touched && school.invalid ? 'has-error' : ''}`}>
                            <label htmlFor="school" className="col-lg-2 control-label">Your School</label>
                            <div className="col-lg-10">
                                <select name="school" className="form-control" {...school}>
                                    <option value="MIT">MIT</option>
                                    <option value="Stanford">Stanford</option>
                                    <option value="Arizona">Arizona</option>
                                </select>
                            </div>
                        </div>
                    </div>
                </div>
                </div>
                <div className="form-submit">
                    <button type="submit" className="btn btn-primary">Book a Payment</button>
                </div>
            </form>
        );
    }
}

function validate(values) {
    const errors = {};

    if (!values.school)
        errors.school = 'School is a required field';

    return errors;
}

export default reduxForm({
    form: 'PaymentBookingForm',
    fields: ['school'],
    validate
}, null, {makeBooking})(PaymentBooking);

this.props after submit:

{
  "readonly": false,
  "asyncValidating": false,
  "dirty": false,
  "errors": {
    "school": "School is a required field"
  },
  "fields": {
    "school": {
      "name": "school",
      "defaultChecked": false,
      "valid": false,
      "invalid": true,
      "dirty": false,
      "pristine": true,
      "error": "School is a required field",
      "active": false,
      "touched": true,
      "visited": false
    }
  },
  "invalid": true,
  "pristine": true,
  "submitting": false,
  "submitFailed": true,
  "valid": false,
  "values": {}
}

Upvotes: 6

Views: 9175

Answers (2)

cheslijones
cheslijones

Reputation: 9194

Late to the game, I found myself in this position just now. I needed to know if there were any active field errors in a Redux-Form so that I could disable the Submit button in the form.

My use case might not be quite the same as OPs, but Andy_D's response got me going in the right direction; however, I didn't find pristine, dirty, or pure useful in my case. Once those are toggled from their default value, they stay that way until the component is reloaded.

valid and invalid do toggle back and forth based on whether the form had errors or did not. So in my case, I can do the following:

<button 
    disabled={ this.props.invalid }
    type='submit' 
    className='btn btn-primary'
>
    Submit
</button>

I tried using something like Redux-Form's formValueSelector() and had no luck there, so this was the best solution I could find that works for me.

Upvotes: 0

Andy_D
Andy_D

Reputation: 4228

It's there in the props for you - you're looking for the form-level props pristine and valid.

After submit, pristine will reset, but if the request is unsuccessful, you'll get a submitFailed prop.

(!pristine || submitFailed) && !valid && <ErrorMessage />

There are also props for the inverses, so you could use

(dirty || submitFailed) && invalid

As I mentioned in my comment, I would prevent submit if the form is invalid.

<button
  type="submit"
  className="btn btn-primary"
  disabled={pristine || invalid}
>Book a Payment</button>

Upvotes: 10

Related Questions