Niveditha Karmegam
Niveditha Karmegam

Reputation: 740

Redux-form validations not getting caught

im fairly new to redux.

What im trying to validate is, two key fields cannot hold the same value and all fields are required. For the required part, i am using Field-Level Validations and that seems to work fine. For deciding whether an element already exists, i am using Sync Validation.

  1. When the sync validation works, i checked it with console log. It catching the error and adding it to the errors object. But my form is not showing that.. is it not binded? What am i missing here?

  2. I have added 'onFocus' and 'onBlur' mouse events to the text-fields, to make then readonly onBlur. They seem to be working fine. But the moment i added that, my {touched && error && <span>{error}</span>} error stops getting displayed. What am i doing wrong here?

my form

const required = value => (value ? "" : "required")
class CreateObject extends React.Component {

    enableTextField = (e) => {
        document.getElementById(e.target.id).removeAttribute("readonly");
    }

    disableTextField = (e) => {
        document.getElementById(e.target.id).setAttribute("readonly", true);
    }

    renderField = ({ input, label, type, id, meta: { touched, error } }) => (

        <React.Fragment>
            {touched && error && <span>{error}</span>}

            <FormControl {...input} type={type} placeholder={label} id={id}
                className={`align-inline object-field-length ${error ? 'error' : ''}`}
                onFocus={this.enableTextField.bind(this)}
                onBlur={this.disableTextField.bind(this)}
            />
        </React.Fragment>
    );

    renderObjects = ({ fields, meta: { touched, error, submitFailed, errors } }) => {
        return (
            <ul>
                <li>
                    <center>
                        <Button bsStyle="success" onClick={() => fields.push({})}>Add New Object</Button>
                    </center>
                </li>
                {fields.map((object, index) => (
                    <li key={index}>
                        <br />
                        <center>
                            <Field
                                name={`${object}.key`}
                                type='text'
                                component={this.renderField}
                                validate={required}
                                label="Key"
                                id={`${object}.key`}
                            />
                            <div className="divider" />
                            <Field
                                name={`${object}.method`}
                                type='text'
                                component={this.renderField}
                                label="Method"
                                validate={required}
                                id={`${object}.key` + `${object}.method`}
                            />
                            <div className="divider" />
                            <Field
                                name={`${object}.value`}
                                type='text'
                                component={this.renderField}
                                label="Value"
                                validate={required}
                                id={`${object}.key` + `${object}.value`}
                            />
                            <div className="divider" />
                            <span
                                className="align-inline"
                                onClick={() => fields.remove(index)}
                                className="allIcons mdi mdi-delete-forever"
                            />

                        </center>
                    </li>
                )

                )}
            </ul>
        );
    }

    submit() {
        //this
    }

    render() {

        const { handleSubmit, pristine, reset, submitting, invalid } = this.props;
        console.log(this.props);
        return (
            <form onSubmit={handleSubmit(this.submit.bind(this))}>
                <FieldArray name='objects' component={this.renderObjects} />
                <center>
                    <Button className="align-inline" type="submit" disabled={pristine || submitting || invalid}>Submit</Button>
                    <div className="divider" />
                    <Button className="align-inline" disabled={pristine || submitting} onClick={reset}> Clear All Values </Button>
                </center>
            </form>
        );
    }
}
export default reduxForm({
    form: 'ObjectRepo',
    validate
})(CreateObject); 

validate.js

const validate = values => {

    const error = {}
    if (!values.objects || !values.objects.length) {
        error.objects = { _error: 'At least one object must be entered' }
    } else {
        const objectArrayErrors = []
        values.objects.forEach((object, objectIndex) => {

            const objectErrors = { _error: 'Object Key should be unique' }
            if (values.objects.filter(item => item.key == object.key).length == 2) {
                objectArrayErrors[objectIndex] = objectErrors
            }
        })
        if (objectArrayErrors.length) {
            error.objects = objectArrayErrors
        }
    }
    console.log(error)
    return error
}

export default validate

Thanks a lot in advance!

Upvotes: 1

Views: 87

Answers (1)

Max Larionov
Max Larionov

Reputation: 474

You might want to look at the code below which works for me. This is your container (or smart component if you wish)

export const validateProps = {
  name: [required],
  value: [required, intOrFloat, maxPercent],
  someId: [required],
}

export const transformer = new TypesModel({
  name: String,
  value: Number,
  someId: Number,
})

export default createFormContainer(
  formName,
  'your_form',
  transformer,
  validateProps,
  mapStateToProps,
  mapDispatchToProps,
  null,
  false,
  null,
  onSuccessSubmit)(YourFormContainer)

And the code for types model is

class TypesModel {
    constructor(schema) {
        this.schema = schema
    }
    transform(data) {
        const keys = Object.keys(this.schema)
        const result = {}
        for (let index = 0, len = keys.length; index < len; index += 1) {
            const keyName = keys[index]
            try {
                result[keyName] = this.schema[keyName](data[keyName])
            } catch (e) {
                throw new Error(`Type conversion for field "${keyName}" failed`)
            }
        }
        return result
    }
}

export default TypesModel

You want validators to look like:

export const required = value => isEmpty(value) &&
  'Required field'
export const intOrFloat = value => (!isInt(`${value}`) && !isFloat(`${value}`)) &&
    'Must be an integer of float'

Upvotes: 1

Related Questions