How to take input to a structured array(nested) using react, Array size will be dynamically decided

Viewed 93

I want to take input in these format from user

"questions":[
        {"question": "Trial question","options":[{"A":"hi","B":"hi","C":"hi","D":"hi"}], "ans":"A","marks":5},
        {"question": "Trial question2","options":[{"A":"hi","B":"hi","C":"hi","D":"hi"}], "ans":"A","marks":1},
        {"question": "Trial question2","options":[{"A":"hi","B":"hi","C":"hi","D":"hi"}], "ans":"A","marks":2}
    ]

Here the array size is dynamic, user can input n number of this structure.(Here size is 3)

I am trying this way to take the input

constructor() {
    super();
    this.state = {
      name: "",
      subject: "",
      numQuestion: 0,
      totalNumQuestion: "",
      questions: [
        {
          question: "",
          options: [
            {
              A: "",
              B: "",
              C: "",
              D: "",
            },
          ],
          marks: "",
          ans: "",
        },
      ],
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }

Here I am taking inputs in following way

for (let i = 1; i <= this.state.numQuestion; i++) {
      inputs.push(
        <input
          placeholder="Question name"
          name={`question`}
          onChange={this.onChange}
          required
        />,
        <br />,
        <input
          placeholder="Option A"
          name={`A`}
          onChange={this.onChange}
          required
        />,

        <input
          placeholder="Option B"
          name={`B`}
          onChange={this.onChange}
          required
        />,

        <input
          placeholder="Option C"
          name={`C`}
          onChange={this.onChange}
          required
        />,

        <input
          placeholder="Option D"
          name={`D`}
          onChange={this.onChange}
          required
        />,
        <br />,
        <input
          placeholder="Answer"
          name={`ans`}
          onChange={this.onChange}
          required
        />,
        <br />,
        <input
          placeholder="Marks"
          name={`marks`}
          onChange={this.onChange}
          required
        />,
        <br />
      );

This is not working. How can i modify the code to achieve the data in structure specified above

1 Answers

You first need to initialize the questions state in componentDidMount based on the numberofQuestions, i realized that the number of questions in current state is zero, not sure whether you get it from user input or set it permanently from your code.

componentDidMount(){
  let quest = [];
  for (let i = 0; i < this.state.numQuestion; i++) {
    quest.push(null)
  }
  this.setState({questions: quest})
}

You would also need a different onChange and onChangeOption function for both options input and other inputs.

const onChange = (index, name, value) => {
  // declare a temp questions array
  const questions = this.state.questions
  // get the current question being changed
  const currentQuestion = questions[index];
  // if question has not been changed/added
  if (!currentQuestion) {
    const newQuestionObject = {
      question: "",
      options: [
        {
          A: "",
          B: "",
          C: "",
          D: "",
        },
      ],
      marks: "",
      ans: "",
    }

    newQuestionObject[name] = value;
    questions[index] = newQuestionObject;
    this.setState({ questions })
  } else {
    currentQuestion[name] = value;
    questions[index] = currentQuestion;
    this.setState({ questions })
  }
}

onChangeOption = (index, name, value) => {
  // declare a temp questions array
  const questions = this.state.questions
  // get the current question being changed
  const currentQuestion = questions[index];
  // if question has not been changed/added
  if (!currentQuestion && currentQuestion.question) {
    const newQuestionObject = {
      question: "",
      options: [
        {
          A: "",
          B: "",
          C: "",
          D: "",
        },
      ],
      marks: "",
      ans: "",
    }

    newQuestionObject.options[0][name] = value;
    questions[index] = newQuestionObject;
    this.setState({ questions })
  } else {
    currentQuestion.options[0][name] = value;
    questions[index] = currentQuestion;
    this.setState({ questions })
  }
}

you can then render the elements


for (let i = 1; i <= this.state.numQuestion; i++) {
  inputs.push(
    <input
      placeholder="Question name"
      name={`question`}
      onChange={(e) => this.onChange(i, e.target.name, e.target.value)}
      required
    />,
    <br />,
    <input
      placeholder="Option A"
      name={`A`}
      onChange={(e) => this.onChangeOption(i, e.target.name, e.target.value)}
      required
    />,

    <input
      placeholder="Option B"
      name={`B`}
      onChange={(e) => this.onChangeOption(i, e.target.name, e.target.value)}
      required
    />,

    <input
      placeholder="Option C"
      name={`C`}
      onChange={(e) => this.onChangeOption(i, e.target.name, e.target.value)}
      required
    />,

    <input
      placeholder="Option D"
      name={`D`}
      onChange={(e) => this.onChangeOption(i, e.target.name, e.target.value)}
      required
    />,
    <br />,
    <input
      placeholder="Answer"
      name={`ans`}
      onChange={(e) => this.onChange(i, e.target.name, e.target.value)}
      required
    />,
    <br />,
    <input
      placeholder="Marks"
      name={`marks`}
      onChange={(e) => this.onChange(i, e.target.name, e.target.value)}
      required
    />,
    <br />
  );
}
Related