I'd like to use a Cleave
(see https://nosir.github.io/cleave.js/ for details) as a Field
inside a Formik
form. While built-in components like text inputs work fine, the Cleave
value change is not recorded and furthermore reset if any other value is changed in the form.
Maybe there's a good explanation why this is a bad idea. I'm confused by the following setup not working out-of-the-box. I expect the value to be not reset and stored in the form's values
which are eventually submitted.
I'm using the following code:
import React from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";
import Cleave from 'cleave.js/react';
class App extends React.Component {
render() {
return <div>
<Formik
initialValues={{ title: "", price: 0 }}
validate={values => {
this.setState({ validationErrorDetails: null, errorMessage: "" });
let errors = {title: "", price: ""};
console.log("validate values", values);
if (!values.price || isNaN(values.price)) {
errors.price = "Price amount is required";
}
return errors;
}}
onSubmit={values => {
alert(JSON.stringify(values));
}}
render={({ isSubmitting, handleSubmit, handleChange, handleBlur, values }) => (
<Form>
<table>
<tbody>
<tr>
<td>
<label>Title:</label>
</td>
<td>
<Field name="title" component="input" />
</td>
<td>
<ErrorMessage name="title" component="div" />
</td>
</tr>
<tr>
<td>
<label>Price:</label>
</td>
<td>
<Field name="price" component={() => <Cleave value={values.price}
options={{numericOnly: true, numeral: true, numeralThousandsGroupStyle: "thousand"}} />}/>
</td>
<td>
<ErrorMessage name="price" component="div" />
</td>
</tr>
</tbody>
</table>
<button type="submit" disabled={isSubmitting} className="confirm-button">
Submit
</button>
</Form>
)}/>
</div>;
}
}
export default App;
and just ReactDOM.render(<App />, document.getElementById('root'))
on the index page. An SSCCE providing the boilerplate, but not more logic is provided at https://gitlab.com/krichter/react-formik-with-cleave.
Formik will not magically bind handleChange
to a <Cleave>
element like it does for <Field>
. You'll need to bind it yourself like this:
<Cleave value={values.price}
options={...}
onChange={handleChange}
/>
Cleave onChange events have both the display value and raw value (e.g. {value: $1,000, rawvalue: 1000}
).
I'm assuming for most implementations you'd want the raw value passed to Formik, so you'll need to add a custom event to the <Cleave>
component.
<Cleave value={values.price}
options={...}
onChange={event => {
const tempEvent = event
tempEvent.target.value = event.target.rawValue
handleChange(tempEvent)
}}
/>