Search code examples
javascriptreactjsreduxredux-form

How to make validation to work for redux-form field generated from an array


I am trying to use redux-form to generate a quiz form. My data source for an individual redux-form field component comes from an array - questions in my case. Everything works as expected except validation. Any thoughts how this can be fixed?

import React from 'react';
import { Field, reduxForm } from 'redux-form';
import { Input, Button } from 'reactstrap';

const validate = values => {
  const errors = {};
  if (!values.question) { // this is just an example of what I am trying to do, validation does not work
    errors.question = 'Required';
  } else if (values.question.length < 15) {
    errors.question = 'Must be 15 characters or more';
  }
  return errors;
};

const renderField = ({ input, label, type, meta: { touched, error } }) => (
  <div>
    <label>{label}</label>
    <div>
      <Input {...input} type={type} />
      {touched && (error && <span>{error}</span>)}
    </div>
  </div>
);

const renderQuestions = questions => {
  return questions.map(question => {
    return (
      <Field key={question.id} name={question.prompt} type="textarea" component={renderField} label={question.prompt} />
    );
  });
};

const QuizStepForm = props => {
  const { handleSubmit, pristine, reset, submitting, questions } = props;
  return (
    <form onSubmit={handleSubmit}>
      <Field name="username" type="textarea" component={renderField} label="username" />
      {renderQuestions(questions)}

      <div>
        <br />
        <Button color="primary" style={{ margin: '10px' }} type="submit" disabled={submitting}>
          Submit
        </Button>
        <Button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </Button>
      </div>
    </form>
  );
};

export default reduxForm({
  form: 'quizStepForm',
  validate
})(QuizStepForm);

Solution

  • Your validation function assumes there is one field named "question." But your code creates a set of fields whose name is set by {question.prompt}. If you stick with this implementation, your validation code will need to know about all the question.prompt array values and check values[question.prompt] for each one, then set errors[question.prompt] for any failures. That would probably work, though it seems like a suboptimal design.

    This might be a good use case for a FieldArray. In FieldArrays, the validation function is called for you on each field; your validation code doesn't have to know the names of all the fields.