skip to Main Content

I am creating form from JSON using react hook form.I am using below library
https://www.react-hook-form.com/

ISSUE : In my JSON Each field have one property "disabled" . On the basis of property I want to disable or enable that field in INITIAL render but after some time I need to enable field at some condition(example first name)

here is my JSON

const json = [
  {
    type: "input",
    name: "firstName",
    label: "First Name",
    disabled: true
  },
  {
    type: "input",
    name: "lastName",
    label: "Last Name",
    disabled: true
  }
];

Need to disable both field initially .But after 5 sec I need to enable first name field.

here is my code
https://codesandbox.io/s/react-hook-form-v7-form-context-forked-hlq9hm?file=/src/index.js

function App() {
  const methods = useForm();

  useEffect(() => {
    setTimeout(() => {
      methods.setValue("firstName.disabled", false);
    }, 5000);
  }, []);

  const onChange = () => {
    console.log("000000");
  };

  const onSubmit = (data) => {
    console.log(data);
  };
  return (
    <FormProvider {...methods}>
      <FormBuilder
        jsonSchema={json}
        defaultValue={defaultValue}
        onSubmitHandler={onSubmit}
        functionHandler={{
          onChange: onChange
        }}
      />
    </FormProvider>
  );
}

JSON render form

export default function FormBuilder({
  jsonSchema,
  functionHandler,
  onSubmitHandler
}) {
  const methods = useFormContext();
  const { register, handleSubmit, getValues, setValue } = methods;

  const onSubmit = (data) => {
    onSubmitHandler(data);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {jsonSchema.map(({ type, name, label, disabled, ...rest }, index) => {
        if (type === "input") {
          return (
            <React.Fragment key={index}>
              <label>{label}</label>
              <input
                {...register(name, { required: true })}
                disabled={getValues("disabled")}
              />
            </React.Fragment>
          );
        }

        // if (type === "select") {
        //   return (
        //     <React.Fragment key={index}>
        //       <label>{label}</label>
        //       <select
        //         {...register(name)}
        //         onChange={
        //           functionHandler[rest.changeHandler]
        //             ? functionHandler[rest.changeHandler]
        //             : null
        //         }
        //       >
        //         {rest.items.map((i, index) => (
        //           <option key={index} value={i.value}>
        //             {i.label}
        //           </option>
        //         ))}
        //       </select>
        //     </React.Fragment>
        //   );
        // }
      })}
      <button type="submit">Submit</button>
    </form>
  );
}

any suggestion ? how to achieve this

2

Answers


  1.  useEffect(() => {
        setTimeout(() => {
          methods.setValue("firstName.disabled", false);
        }, 5000);
      }, []);
    

    Hi, instead of updating the disabled property using setValue you can update it using state

    const [newJson , setNewJson] = useState(json)
    useEffect(() => {
    
    
        setTimeout(() => {
             setNewJson(list => list.map((item, i) => // Array.protptype.map creates new 
     array
               i === 0
                ? {                               // new object reference for updated item
                 ...item,                        // shallow copy previous item state
                 disabled: false             // overwrite property being updated
              }
                : item
            ));
          }, 5000);
        }, []);
    

    And then create new useEffect which depends on newJson value whenever its value get update the view will be re render

    useEffect(() => {
    
    }, [newJson])
    

    After that pass newJson in props instead of json property like below

    <FormProvider {...methods}>
      <FormBuilder
        jsonSchema={newJson}
        defaultValue={defaultValue}
        onSubmitHandler={onSubmit}
        functionHandler={{
          onChange: onChange
        }}
      />
    </FormProvider>
    

    Then in formbuilder.js update the code. Instead of using getValue function we can directly access disabled property.

           <React.Fragment key={index}>
              <label>{label}</label>
              <input
                {...register(name, { required: true })}
                disabled={disabled}
              />
            </React.Fragment>
    

    I hope this will help you. Please let me know if there is any doubt. Thanks

    Login or Signup to reply.
  2. Did you try to update the json itself for a workaround. I tried in your codesandbox

    Try the following code (I have removed unused code, you please add as your requirement) [Look at the useEffect part, updating the json itself]

    1. index.js
    import React, { useEffect, useState } from "react";
    import ReactDOM from "react-dom";
    import { useForm, FormProvider } from "react-hook-form";
    import FormBuilder from "./formbuilder";
    
    import "./styles.css";
    
    const defaultValue = { firstName: "", person: { sex: "" } };
    const json = [
      {
        type: "input",
        name: "firstName",
        label: "First Name",
        disabled: true
      },
      {
        type: "input",
        name: "lastName",
        label: "Last Name",
        disabled: true
      }
    ];
    
    function App() {
      const [jsonSchema, setJsonSchema] = useState(json);
      const methods = useForm();
    
      useEffect(() => {
        setTimeout(() => {
          setJsonSchema((prev) => {
            const cloned = [...prev];
            const firstNameIndex = cloned.findIndex((j) => j.name === "firstName");
            if (firstNameIndex > -1) {
              cloned[firstNameIndex].disabled = false;
            }
            return cloned;
          });
        }, 5000);
      }, []);
    
      const onChange = () => {
        console.log("000000");
      };
    
      const onSubmit = (data) => {
        console.log(data);
      };
      return (
        <FormProvider {...methods}>
          <FormBuilder
            jsonSchema={jsonSchema}
            defaultValue={defaultValue}
            onSubmitHandler={onSubmit}
            functionHandler={{
              onChange: onChange
            }}
          />
        </FormProvider>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    
    1. formbuilder.js
    import React from "react";
    import { useFormContext } from "react-hook-form";
    export default function FormBuilder({ jsonSchema, onSubmitHandler }) {
      const methods = useFormContext();
      const { register, handleSubmit } = methods;
    
      const onSubmit = (data) => {
        onSubmitHandler(data);
      };
    
      return (
        <form onSubmit={handleSubmit(onSubmit)}>
          {jsonSchema.map(({ type, name, label, disabled }, index) => {
            if (type === "input") {
              return (
                <React.Fragment key={index}>
                  <label>{label}</label>
                  <input
                    disabled={disabled}
                    {...register(name, { required: true })}
                  />
                </React.Fragment>
              );
            }
            return <></>;
          })}
          <button type="submit">Submit</button>
        </form>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search