skip to Main Content

I’ve had a look for any similar questions related to this but couldn’t anything. Basically I am using formik to manage questions for a quiz. I am using FieldArray to dynamically add question text boxes and possible answers. I am currently struggling to validate the nested values. Here are my initial values and the validate function.

  const validate = (fields: QuestionFields) => {
    const errors: any = {};
    if (!errors.questions) {
      errors.questions = [];
    }
    fields.questions.forEach((q, i) => {
      if (!q.questionText) {
        errors.questions[i] = {
          questionText: 'A question is required.',
          answers: '',
        };
      }

      const isValid = q.answers.some((a) => a.text && a.isCorrectChoice);
      if (!isValid) {
      }
    });

    return errors;
  };

  const question = {
    questionText: '',
    questionImage: '',
    answers: [
      {
        text: '',
        isCorrectChoice: false,
      },
      {
        text: '',
        isCorrectChoice: false,
      },
      {
        text: '',
        isCorrectChoice: false,
      },
      {
        text: '',
        isCorrectChoice: false,
      },
    ],
  };

  const initialValues: QuestionFields = {
    questions: [question],
  };

The main issue is how to check that an answer has been provided for each of the questions. That is when the user does not enter any text for the text inside the answers array how do I add this to the error object in order to check each questions answers array has some text and is not empty. I then want to use this error object inside the render prop via the errors object that is injected.

I have tried a few approaches but I keep getting an error when I add a new question.

Thanks in advance.

2

Answers


  1. Chosen as BEST ANSWER

    Ok so for anyone that is having a similar issue with nested items. Here is my solution:

      const validate = (fields: QuestionFields) => {
        const errors: any = {};
    
        fields.questions.forEach((q, i) => {
          if (!q.questionText) {
            if (!errors.questions) {
              errors.questions = [];
              errors.questions[i] = { questionText: 'A question is required.' };
            } else {
              console.log('here', errors);
              // if errors.questions and fields.questions do not match up
              if (errors.questions.length !== fields.questions.length) {
                errors.questions[i] = { questionText: 'A question is required.' };
              } else {
                errors.questions[i].questionText = 'A question is required.';
              }
            }
          }
    
          const isValid = q.answers.some((a) => a.text && a.isCorrectChoice);
          if (!isValid) {
            if (!errors.questions) {
              errors.questions = [];
              errors.questions[i] = { answers: 'A correct answer is required.' };
            } else {
              if (errors.questions.length !== fields.questions.length) {
                errors.questions[i] = { answers: 'A correct answer is required.' };
              } else {
                errors.questions[i].answers = 'A correct answer is required.';
              }
            }
          }
        });
        return errors;
      };
    

    The gist of it is that you have to keep track of the fields length and the errors length for any array items and then add each error accordingly. Hopefully this is helpful to someone.


  2. You can try this

    fields.questions.forEach((q, i) => {
      if (!q.questionText) {
        errors[`questions[$[i]]`]["questionText"] = "A question is required.";
      }
    
      const isValid = q.answers.some((a) => a.text && a.isCorrectChoice);
      if (!isValid) {
        errors[`questions[$[i]]`]["answers"] = "Atleast one correct answer is required";
    
      }
    });
    

    You can access this error msg like this

    errors[`options[${index}]`]['questionText/answer']

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search