3
\$\begingroup\$

I have a array-object which should look something like this and is used to create a form

const questions = [
  {
    condition_action: "selected",
    label: "What is your name?",
    question_type: "free_text",
    required: true,
  },
  {
    condition_action: "selected",
    label: "Where do you live?",
    question_options: [
      {
        label: "India",
      },
      {
        label: "china",
      },
      {
        label: "japan",
      },
    ],
    question_type: "single_answer",
    required: false,
  },
];

Now, When user is done creating the form, I have to validate the data and add a key name order in the above snippet (more below) to array-object (main array and question_options)

For validation, There are two conditions

  1. Main array-object should have a label (if not throw error).
  2. Question option should have at-least 1 item and the label inside it can't be empty

Basically, question_options is for multiple-select and single select drop down. So question_option should only contain value if question_type key in the above snippet is single_answer or multiple_answer

The backend api also require attribute order on the main question array and question_options array (yeah even though it's an array we could determine the order through index)

So this is the code I wrote

   const validateAndFormatdata = (questions) => {
    // we will change this to true if error exist and send it at return of this function
    let errorsExsist = false
    // we are formating data here, if error exist while validation, we change flag
    const formatedData = (questions || []).map((question, index) => {
      // delete all previous errors since we are iterating and we don't care about our previous errors
      if (Object.prototype.hasOwnProperty.call(question, "errors")) {
        delete question.errors
      }
      // There can be more than one thing wrong, hence using an array
      const newErrors = []
      // if label does not have value, add it it in errors array
      if (question.label === "") {
        newErrors.push(errorReasons.missingLabel)
      }
      if (
        question.question_type === "multiple_answer" ||
        question.question_type === "single_answer"
      ) {
        const questionOptions = _.filter(question.question_options, "label").map(
          (option, position) => {
            return {
              ...option,
              order: position
            }
          }
        )
        // if question optiond does not have single item, add it it in errors array
        if (questionOptions.length < 1) {
          newErrors.push(errorReasons.noOption)
        } else {
          question.question_options = [...questionOptions]
        }
      } else if (Object.prototype.hasOwnProperty.call(question, "question_options")) {
        // remove question otpions of question type isn't single or mult-text
        delete question.question_options
      }

      if (newErrors.length > 0) {
        errorsExsist = true
        question.errors = newErrors
      }
      return { ...question, order: index }
    })
    return {
      errorsExsist,
      data: formatedData
    }
  }

Question: I was wondering if someone can share review, optimisation and suggestions (including naming)?

\$\endgroup\$
1
\$\begingroup\$

I have made some changes and added comments for each change.

// add the default array here ------------↓ 
const validateAndFormatdata = (questions = []) => {
  let errorsExist = false, // <- typo in exist
      // in case you want to add new types
      optionTypes = new Set(["multiple_answer", "single_answer"]);
      
  // no need to check for || [] because default is added
  // remove the errors property here itself by using destructuring
  const formattedData = questions.map(({ errors, question_options, ...question }, index) => {
    // because of the destructuring, question is a new object.
    // So, will not mutate the original object
    question.order = index;

    const newErrors = []
    
    // checks if label exists and if it is an empty string
    if (!question.label) {
      newErrors.push(errorReasons.missingLabel)
    }
    
    if (optionTypes.has(question.question_type)) {
      const questionOptions = question_options
                                    .filter(q => q.label)
                                    .map((option, order) => ({ ...option, order }));
                                      
      // === 0 is much more clearer to read
      if (questionOptions.length === 0) {
        newErrors.push(errorReasons.noOption)
      } else {
        // no need for [...]. It's a new array
        question.question_options = questionOptions
      }
    }
    // no need for delete question.question_options because it is destructured

    if (newErrors.length > 0) {
      errorsExist = true
      question.errors = newErrors
    }

    return question;
  })
  
  return {
    errorsExist,
    data: formattedData
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.