React JS Render Form With Dynamic Data From Backend API

including field validations

We need to plot a form whose entire fields are coming from the backend. Since the fields are not known in advance, we cannot add them statically. The data about each field, such as its id to save with, name, validations, etc. all comes in the API response too.

For the given scenario, I have used React Hook Form. The demo and example code for a dynamic questionnaire is shared below.

Demo


Example Code

import React, { useState } from "react";
import { useForm, useFieldArray } from "react-hook-form";

export default function DynamicForm() {
  const {
    control,
    register,
    handleSubmit,
    watch,
    formState: { errors }
  } = useForm();
  const [loading, setLoading] = useState(false);

  const { fields, append } = useFieldArray({
    control,
    name: "questionnaire"
  });

  const value = watch("questionnaire");

  const questionnaireFromBackend = [
    {
      id: 1,
      value: "",
      placeholder: "First Name",
      required: true
    },
    {
      id: 2,
      value: "",
      placeholder: "Middle Name"
    },
    {
      id: 3,
      value: "",
      placeholder: "Last Name",
      required: true
    }
  ];

  const loadQuestionnaire = () => {
    setLoading(true);
    setTimeout(() => {
      setLoading(false);
      questionnaireFromBackend.forEach((q) => {
        append(q, { shouldFocus: false });
      });
    }, 3000);
  }

  const onSubmit = (data) => {
    console.log(data);
    // submit dynamic questionnaire!
  };

  return (
    <div
      style={{
        borderStyle: "ridge",
        padding: "10px",
        minHeight: "300px"
      }}>

      {
        (!loading && !fields.length)
        &&
        <button
          type="button"
          onClick={loadQuestionnaire}>
          Load Questionnaire
        </button>
      }

      {loading ? (
        "loading questionnaire..."
      ) : (
        <form onSubmit={handleSubmit(onSubmit)}>
          <div>
            {fields.map((field, index) => (
              <div key={field.id} style={{ marginBottom: "10px" }}>
                <input
                  {...register(`questionnaire.${index}.value`, {
                    required: value[index].required
                  })}
                  placeholder={value[index].placeholder}
                />
                <br></br>

                {errors?.questionnaire?.[index] && (
                  <span style={{ color: "red", fontSize: "small" }}>
                    {value[index].placeholder} is required
                  </span>
                )}
              </div>
            ))}
          </div>

          <br></br>
          {!loading && fields.length > 0 && <input type="submit" />}
        </form>
      )}
    </div>
  )
}

In this next post I’m going to share how to handle dynamic conditional fields in a form.




See also

When you purchase through links on techighness.com, I may earn an affiliate commission.