0

I have a form where and I am validating the form using Formik, I want to multiply the value on the quantity input and unit cost input when there's an input and then automatically display it in the total input. I'm using Formik + Chakra_UI.

<Formik
        initialValues={{
          productName: "",
          productNumber: "",
          unitCost: 0,
          totalCost: 0,
          quantity: 0,
        }}
      >
        {({ values }) => (
          <Form>
            <Field name="productName">
              {() => (
                <Grid templateColumns="repeat(2, 1fr)" gap={5}>
                  <Box>
                    <FormControl>
                      <FormLabel htmlFor="productName">Product Name:</FormLabel>
                      <Input id="productName" placeholder="Product Name" />
                      {/* <FormErrorMessage>{form.errors.name}</FormErrorMessage> */}
                    </FormControl>
                  </Box>
                  <Box>
                    <FormControl>
                      <FormLabel htmlFor="productNumber">
                        Product Number:
                      </FormLabel>
                      <Input id="productNumber" placeholder="Product Number" />
                      {/* <FormErrorMessage>{form.errors.name}</FormErrorMessage> */}
                    </FormControl>
                  </Box>
                  <Box>
                    <FormControl>
                      <FormLabel htmlFor="quantity">Quantity:</FormLabel>
                      <Input id="quantity" placeholder="Quanity" />
                      {/* <FormErrorMessage>{form.errors.name}</FormErrorMessage> */}
                    </FormControl>
                  </Box>
                  <Box>
                    <FormControl>
                      <FormLabel htmlFor="unitCost">Unit Cost:</FormLabel>
                      <Input id="unitCost" placeholder="Unit Cost" />
                      {/* <FormErrorMessage>{form.errors.name}</FormErrorMessage> */}
                    </FormControl>
                  </Box>
                  <Box>
                    <FormControl>
                      <FormLabel htmlFor="totalCost">Total Cost:</FormLabel>
                      <Input id="totalCost" placeholder="Total Cost" />
                      {/* <FormErrorMessage>{form.errors.name}</FormErrorMessage> */}
                    </FormControl>
                  </Box>
                </Grid>
              )}
            </Field>
            <Button isFullWidth mt={6} colorScheme="green" type="submit">
              Submit
            </Button>
          </Form>
        )}
      </Formik>
halfer
  • 19,824
  • 17
  • 99
  • 186
AbdulAzeez Olanrewaju
  • 976
  • 1
  • 13
  • 32

1 Answers1

0

To keep code for state management shorter you could just remove totalCost from values and compute it on use.

Updated code would look like this:

<Formik
    initialValues={{
        productName: "",
        productNumber: "",
        unitCost: 0,
        quantity: 0,
    }}
    onSubmit={...}
>
    {({ values }) => (
        <Form>
            <Grid templateColumns="repeat(2, 1fr)" gap={5}>
                // ... other boxes stay same as before
                <Box>
                    <FormControl>
                        <FormLabel htmlFor="totalCost">Total Cost:</FormLabel>
                        <Input id="totalCost" placeholder="Total Cost" value={values.quantity * values.unitCost} />
                        {/* <FormErrorMessage>{form.errors.name}</FormErrorMessage> */}
                    </FormControl>
                </Box>
            </Grid>
            <Button isFullWidth mt={6} colorScheme="green" type="submit">
                Submit
            </Button>
    </Form>)}
</Formik>

then you'll repeat same calculation for onSubmit. Coult be also good idea to apply some rounding on as I assume you use it for currency value={values.quantity * values.unitCost}

maybe you could just simplify it to

    <FormControl>
        <FormLabel htmlFor="totalCost">Total Cost:</FormLabel>
        <Box id="totalCost">{Math.round((values.quantity * values.unitCos + Number.EPSILON) * 100) / 100}</Box>
    </FormControl>

rounding explained here: Round to at most 2 decimal places (only if necessary)

Jaroslav Kadlec
  • 2,505
  • 4
  • 32
  • 43