I'm using formik react library and trying to update 2 fields, based on the onChange event of another. For example,
price = quantity * totalPrice
price :
onChange={() => {setFieldValue('quantity',values.quantity? values.price / values.totalPrice:values.quantity, );
setFieldValue('totalPrice',values.totalPrice? values.price * values.quantity: values.totalPrice,);}}
quantity :
onChange={(value, e) => { this.disableFiled(value, e); setFieldValue('totalPrice',values.price ? values.price * values.totalPrice : ' ',);}}
totalPrice:
onChange={(value, e) => { this.disableFiled(value, e);setFieldValue('quantity',values.price ? values.totalPrice / price : ' ', ); }}
when quantity has value, total price will be disabled and vice versa.but it doesn't calculate other fields correctly
I'm using formik react library and trying to update 2 fields, based on the onChange event of another. For example,
price = quantity * totalPrice
price :
onChange={() => {setFieldValue('quantity',values.quantity? values.price / values.totalPrice:values.quantity, );
setFieldValue('totalPrice',values.totalPrice? values.price * values.quantity: values.totalPrice,);}}
quantity :
onChange={(value, e) => { this.disableFiled(value, e); setFieldValue('totalPrice',values.price ? values.price * values.totalPrice : ' ',);}}
totalPrice:
onChange={(value, e) => { this.disableFiled(value, e);setFieldValue('quantity',values.price ? values.totalPrice / price : ' ', ); }}
when quantity has value, total price will be disabled and vice versa.but it doesn't calculate other fields correctly
Share Improve this question edited Sep 24, 2019 at 10:34 Rahele Nazari asked Sep 24, 2019 at 8:32 Rahele NazariRahele Nazari 4012 gold badges5 silver badges13 bronze badges2 Answers
Reset to default 12This is how I do this.
App.js file:
import React from "react";
import "./styles.css";
import { Formik } from "formik";
import * as Yup from "yup";
import CalculatedField from "./CalculatedField";
const App = () => (
<div className="app">
<Formik
initialValues={{ price: "", quantity: "", totalPrice: "" }}
onSubmit={async values => {
await new Promise(resolve => setTimeout(resolve, 500));
alert(JSON.stringify(values, null, 2));
}}
validationSchema={Yup.object().shape({
price: Yup.number("It's a number").required("Required"),
quantity: Yup.number("It's a number").required("Required"),
totalPrice: Yup.number("It's a number").required("Required")
})}
>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
setFieldValue
} = props;
return (
<form onSubmit={handleSubmit}>
<div className="input-row">
<label htmlFor="quantity" style={{ display: "block" }}>
Quantity
</label>
<input
id="quantity"
name="quantity"
placeholder="Enter quantity"
type="number"
value={values.quantity}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.quantity && touched.quantity
? "text-input error"
: "text-input"
}
/>
{errors.quantity && touched.quantity && (
<div className="input-feedback">{errors.quantity}</div>
)}
</div>
<div className="input-row">
<label htmlFor="price" style={{ display: "block" }}>
Price
</label>
<input
id="price"
name="price"
placeholder="Enter your price"
type="number"
value={values.price}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.price && touched.price
? "text-input error"
: "text-input"
}
/>
{errors.price && touched.price && (
<div className="input-feedback">{errors.price}</div>
)}
</div>
<div className="input-row">
<label htmlFor="totalPrice" style={{ display: "block" }}>
Total Price
</label>
<CalculatedField
id="totalPrice"
type="number"
name="totalPrice"
value={values.totalPrice}
values={values}
setFieldValue={setFieldValue}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.totalPrice && touched.totalPrice
? "text-input error"
: "text-input"
}
/>
{errors.totalPrice && touched.totalPrice && (
<div className="input-feedback">{errors.totalPrice}</div>
)}
</div>
<div className="input-row">
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</div>
</form>
);
}}
</Formik>
</div>
);
export default App;
CalculatedField.js
import React, { useEffect } from "react";
const CalculatedField = props => {
useEffect(() => {
var val = 0;
if (props.values.price && props.values.quantity) {
val = props.values.price * props.values.quantity;
}
props.setFieldValue("totalPrice", val);
}, [props.values]);
return (
<input
id="totalPrice"
type="number"
name="totalPrice"
value={props.values.totalPrice}
/>
);
};
export default CalculatedField;
This is basically achieved by calling setFieldValue method within useEffect hooks in the CalculatedField component. Please remember useEffect will watch for the change of the values and run the setFieldValue method when they are modified.
Please follow the CodeSandbox demo. https://codesandbox.io/s/affectionate-mirzakhani-who30?file=/src/App.js
Check this out it may help :
https://github.com/jaredpalmer/formik/issues/1840
you have to call handleChange(e)
on-field change!