nathan evans
nathan evans

Reputation: 25

Dependent Field React FormIK - Value of last Field Depends on the Two Other Fields

I have 3 fields in a form: fieldA fieldB fieldC.

What I want: I want the third field that the user has yet to fill to be a function of the other two. E.g. If you set field fieldA and fieldB to 1 and 2 respectively, I want fieldC to be 1/2. How do I get the this dynamic, dependent field to work?

I am currently using the package FormIK but will accept any answer.

This is my current build:

const MyFieldC = (props) => {
  const {
    values: { textA, textB },
    touched,
    setFieldValue,
  } = useFormikContext();
  const [field, meta] = useField(props);

  React.useEffect(() => {
    // set the value of textC, based on textA and textB
    if (
      textA.trim() !== '' &&
      textB.trim() !== '' &&
      touched.textA &&
      touched.textB
    ) {
      setFieldValue(props.name, textA/textB);
    }
  }, [textB, textA, touched.textA, touched.textB, setFieldValue, props.name]);

  return (
    <>
      <input {...props} {...field} />
      {!!meta.touched && !!meta.error && <div>{meta.error}</div>}
    </>
  );
};

const MyFieldA = (props) => {
  const {
    values: { textC, textB },
    touched,
    setFieldValue,
  } = useFormikContext();
  const [field, meta] = useField(props);

  React.useEffect(() => {
    // set the value of textC, based on textA and textB
    if (
      textC.trim() !== '' &&
      textB.trim() !== '' &&
      touched.textA &&
      touched.textB
    ) {
      setFieldValue(props.name, textA/textB);
    }
  }, [textB, textC, touched.textA, touched.textB, setFieldValue, props.name]);

  return (
    <>
      <input {...props} {...field} />
      {!!meta.touched && !!meta.error && <div>{meta.error}</div>}
    </>
  );
};

const MyFieldB = (props) => {
  const {
    values: { textA, textC },
    touched,
    setFieldValue,
  } = useFormikContext();
  const [field, meta] = useField(props);

  React.useEffect(() => {
    // set the value of textC, based on textA and textB
    if (
      textA.trim() !== '' &&
      textC.trim() !== '' &&
      touched.textA &&
      touched.textC
    ) {
      setFieldValue(props.name, textA/textC);
    }
  }, [textC, textA, touched.textA, touched.textC, setFieldValue, props.name]);

  return (
    <>
      <input {...props} {...field} />
      {!!meta.touched && !!meta.error && <div>{meta.error}</div>}
    </>
  );
};

function Form() {
  // Note that we provide initalValues all 3 fields.
  const initialValues = { textA: '', textB: '', textC: '' };
  return (
    <div className="App">
      <Formik
        initialValues={initialValues}
        onSubmit={async (values) => alert(JSON.stringify(values, null, 2))}
      >
        <div className="section">
          <Form>
            <label>
              FieldA
              <MyFieldA name="textA" />
            </label>
            <label>
              FieldB
              <MyFieldB name="textB" />
            </label>
            <label>
              FieldC
              <MyFieldC name="textC" />
            </label>
            <button type="submit">Submit</button>
          </Form>
        </div>
      </Formik>
    </div>
  );
}

If i submit values for 2 of the 3 values, I get the error:

TypeError: textB.trim is not a function

Upvotes: 2

Views: 899

Answers (1)

Samira
Samira

Reputation: 2733

you can use values props and change the value of fieldC.

const initialValues={textA:'',textB :''}   

  <Formik
            initialValues={initialValues}
            onSubmit={async (values) => alert(JSON.stringify(values, null, 2))}
          >
           {({values}) => (
             <Form>
                <label>
                  FieldA
                  <MyFieldA name="textA" />
                </label>
                <label>
                  FieldB
                  <MyFieldB name="textB" />
                </label>
                <label>
                  FieldC
                  <MyFieldC name="textC" value={(values.textA && values.textB )
     ? (values.textA/values.textB) : ''}/>
                </label>
                <button type="submit">Submit</button>
              </Form>
           )}
         </Formik>

Upvotes: 1

Related Questions