skip to Main Content

the requirement is a bit tricky. dunno how to explain it but I’ll try.

so I’ve 20 forms on my web page. and there’s only one submit button that’ll bulk-submit all the forms. but filling out all forms isn’t required. the user will fill up as many forms as they like. but whichever form they fill up, must be fully filled. means all inputs are required on each form.

so I need to write a logic that’ll make all the inputs required in a form if any of the input is filled there. I know I can use the onChange function and write a logic to make all the input required in one form. but I also need to remove the required from the inputs, if all the input field is again cleared. and I think removing the required from the inputs is the main complexity here. Because while adding required i can simply check if any of the inputs have value in it (using onChange on every input). but if I do the same for removing required, I can’t be assured if one input field is cleared or all the inputs are cleared from that form. so in simpler words, I need to sync all the inputs on each form.

[NOTE-1: I’m in a React environment, so I’ve all the facilities of states and stuff] [NOTE-2: I’ve made a react component for the form and looped over it 20 times. so you can think that as one form] [NOTE-3: This is one of my client’s projects. so I can’t have changes to the requirements]

2

Answers


  1. This is a pretty "business specific" problem, but I would tackle it along these lines. You may need to make adjustments to fit your exact requirements, but the general gist is there.

    The key is to treat the "required" flag for each input as "derived" or calculated state. You said "but I also need to remove the required from the inputs" – I don’t think that’s entirely true, or doesn’t fit the react model. You just need to check if other fields are populated in the current form in the current render.

    const { useState } = React;
    const { render } = ReactDOM;
    
    const forms = [
      {
        inputs: ["field1", "field2"]
      },
      {
        inputs: ["field3", "field4"]
      }
    ];
    
    function MegaForm() {
      const [values, setValues] = useState(() => {
        const values = {};
        forms.forEach((form) => {
          form.inputs.forEach((input) => {
            values[input] = "";
          });
        });
    
        return values;
      });
    
      const submit = () => {
        console.log(values);
      };
    
      const isRequired = (formIndex) => {
        return forms[formIndex].inputs.find(
          (inputName) => values[inputName] !== ""
        );
      };
    
      return (
        <div>
          {forms.map((form, i) => (
            <form key={i}>
              <h2>Form {i}</h2>
              {form.inputs.map((input, j) => (
                <div key={j}>
                  <label>
                    {input}
                    <input
                      value={values[input]}
                      onChange={(e) =>
                        setValues({ ...values, [input]: e.target.value })
                      }
                      required={isRequired(i)}
                    />
                    {isRequired(i) ? "*" : ""}
                  </label>
                </div>
              ))}
            </form>
          ))}
          <br />
          <br />
          <button type="button" onClick={submit}>
            Submit
          </button>
        </div>
      );
    }
    
    render(<MegaForm />, document.getElementById("app"));
    

    CodePen: https://codepen.io/chrisk7777/pen/RwYWWqV?editors=0010

    Login or Signup to reply.
  2. If you have all the forms with the same fields you could go with a solution like this:

    export function FormsContainer() {
      const [formData, setFormData] = React.useState({});
    
      function onChangeGenerator(i: number) {
        return (e) => {
          setFormData((data) => ({
            ...data,
            [i]: {
              ...data[i],
              [e.target.name]: e.target.value,
            },
          }));
        };
      }
    
      function fieldHasValue(value) {
        return value !== null && value !== undefined && value !== '';
      }
    
      function formHasValidFields(i) {
        return (
          formData[i] &&
          Object.keys(formData[i]).some((key) => fieldHasValue(formData[i][key]))
        );
      }
    
      function submit() {
        const result = Object.keys(formData).reduce((acc, i) => {
          if (formHasValidFields(i)) {
            acc.push(formData[i]);
          }
    
          return acc;
        }, []);
    
        console.log(result);
      }
    
      return (
        <form
          onSubmit={(e) => {
            e.preventDefault();
            submit();
          }}
        >
          {[0, 1, 2, 3, 4, 5].map((i) => (
            <SingleForm
              key={i}
              onChange={onChangeGenerator(i)}
              required={formHasValidFields(i)}
            />
          ))}
          <br />
          <br />
          <button type="submit">Submit</button>
        </form>
      );
    }
    
    
    function SingleForm({
      required,
      onChange,
    }: {
      required: boolean;
      onChange: (e) => void;
    }) {
      return (
        <React.Fragment>
          <hr />
          <input name="prop1" onChange={onChange} required={required} />
          <input name="prop2" onChange={onChange} required={required} />
        </React.Fragment>
      );
    }
    

    StackBlitz: https://stackblitz.com/edit/react-ts-utrgbj

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