1

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.

Kalle Richter
  • 8,008
  • 26
  • 77
  • 177

1 Answers1

4

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)
        }}
/>
fralewsmi
  • 92
  • 2
  • 12
  • 1
    Thanks for you input. It sounds reasonable. However, including your suggestion into my SSCCE doesn't change the behaviour. I'm typing `1` into the amount and the typing `a` into the title resets the amount input. – Kalle Richter Jun 30 '19 at 21:00
  • You could try adding the `` outside of the `` component wrapper, and give it the `name="price"` attribute. – fralewsmi Jun 30 '19 at 22:19
  • 1
    That brings a huge improvment, thanks. Now the only issue I see is that the cursor of the cleave jumps to the end of at every value change which is pretty annoying if you want to add digits not at the end. Do you have an idea for that as well. I changed the SSCCE to contain your solution at https://gitlab.com/krichter/react-formik-with-cleave/tree/separate-cleave. – Kalle Richter Jul 01 '19 at 08:13
  • I just noticed I have the same effect, not really sure why. Might be cause for an issue report https://github.com/nosir/cleave.js/issues. There are even a few related issues which appear to be fixed (https://github.com/nosir/cleave.js/issues/385, https://github.com/nosir/cleave.js/issues/301 ...) – fralewsmi Jul 01 '19 at 23:11
  • 1
    Thanks for your support. I think that the combination of advise and hint to the issue reports is worth considering it as the correct answer. I'll post the link to the issue in case I file one. – Kalle Richter Jul 02 '19 at 07:30