Formik: Save on field blur

Created on 6 Sep 2017  路  8Comments  路  Source: formium/formik

How would I use formik if I had a form with some fields that I want to save each time a field loses focus?

Question

Most helpful comment

@bogdansoare you need to pass custom onBlur function for a field you want to change blur event for, some kind of this:

class UserForm extends Component {
  handleEmailFieldBlur = (e) => {
    this.props.handleBlur(e)

    // do something
    saveUserForm(this.props.values)    
  }

  render() {
    const { handleChange, handleSubmit, values } = this.props

    return (
      <form onSubmit={handleSubmit}>
        <input
          id="email"
          type="text"
          value={values.email}
          onChange={handleChange}
          onBlur={this.handleEmailFieldBlur}
        />
        ...
      </form>
    )
  }
}

All 8 comments

@bogdansoare you need to pass custom onBlur function for a field you want to change blur event for, some kind of this:

class UserForm extends Component {
  handleEmailFieldBlur = (e) => {
    this.props.handleBlur(e)

    // do something
    saveUserForm(this.props.values)    
  }

  render() {
    const { handleChange, handleSubmit, values } = this.props

    return (
      <form onSubmit={handleSubmit}>
        <input
          id="email"
          type="text"
          value={values.email}
          onChange={handleChange}
          onBlur={this.handleEmailFieldBlur}
        />
        ...
      </form>
    )
  }
}

@VladShcherbin cool, thank you for the example 鉂わ笍

@jaredpalmer @VladShcherbin I'm having some trouble using this pattern with the new render props, because I don't have handleBlur in the props of the component.
Could you please help me with an example of how you would do this with render props?
Thank you.

How to do this for onChange handle.
I have to form fields. I need to calculate percentage and amount based on these 2 fields.
example: Field 1: Percentage, Feild 2: Amount
So on change of Field1 should calculate the amount and update value in Field 2.

How to achieve this onChange = { e => onChange(e) .... }

How to do this for onChange handle.
I have to form fields. I need to calculate percentage and amount based on these 2 fields.
example: Field 1: Percentage, Feild 2: Amount
So on change of Field1 should calculate the amount and update value in Field 2.

How to achieve this onChange = { e => onChange(e) .... }

<input type="text" name="percentage" onChange={handlePercentageChange} />
<input type="text" name="amount" onChange={handleAmountChange} />

function handlePercentageChange(e) {
  const amount = getAmount(e.target.value);
  formik.handleChange(e);
  formik.setFieldValue('amount',  amount);
}

function handleAmountChange(e) {
  const percentage = getPercentage(e.target.value);
  formik.handleChange(e);
  formik.setFieldValue('percentage',  percentage);
}

@miturostislav Hey thanks for your time.
I have written similar code but it's not working. I am using formik class Component like following code

class MyForm extends Component {
handlePercentageChange =(e) => {
  const amount = getAmount(e.target.value);
  formik.handleChange(e);
  formik.setFieldValue('amount',  amount);
}

handleAmountChange = (e) => {
  const percentage = getPercentage(e.target.value);
  formik.handleChange(e);
  formik.setFieldValue('percentage',  percentage);
}
render() {
const { values, handleSubmit, handleBlur,....} = this.props;
return(
<Form onSubmit={hanldeSubmit}>
   <FormControl
name="amount"
onChangle={handleChange}
value={values.amount}
/>
</Form>
)
}
}
export default withFormik({})()

How to write this calculation in my case.

Thanks in advance.

Hey @Randore, it will great if you could provide a real example for me to see what errors you have.
What I see here is that you should call "withFormik" with an object that contains at least handleSubmit and mapPropsToValues methods. Also you need to do other adjustments as well.
Here is your example after some adjustments, but if it doesn't work for you, make an example and I will have a pleasure to help you.

class MyForm extends Component {
handlePercentageChange =(e) => {
  const amount = getAmount(e.target.value);
  this.props.handleChange(e);
  this.props.setFieldValue('amount',  amount);
}

handleAmountChange = (e) => {
  const percentage = getPercentage(e.target.value);
  this.props.handleChange(e);
  this.props.setFieldValue('percentage',  percentage);
}
render() {
const { values } = this.props;
return(
<Form>
   <FormControl
      name="amount"
      onChange={handleAmountChange}
      value={values.amount}
    />
    <FormControl
        name="percentage"
        onChange={handlePercentageChange}
        value={values.percentage}
    />
</Form>
)
}
}
export default withFormik({
  mapPropsToValues: props => ({ amount: '', percentage: '' }),
  handleSubmit: () => {}
})(MyForm)

Here's my solution with the Formik's field.onBlur prop. Wrapped Formik's onBlur handler with my own. Had to resort to a setTimeout as it seems field.touched and field.errors aren't immediately available after formik's onBlur event is called:


...
<Field name={name} id={name} component={CustomInputText} />
...

class CustomInputText extends React.PureComponent {
    handleBlur = e => {
        const {
            field: { name, onBlur },
        } = this.props;

        onBlur(e);

        // The latest touched and errors aren't available until after the
        // formik's onBlur handler has been called. Setting a timeout allows us
        // to access the proper touched and errors after onBlur event has
        // occurred.
        setTimeout(() => {
            const {
                form: { touched, errors },
            } = this.props;
            const isError = touched[name] && errors[name];
            const isSuccess = touched[name] && !errors[name];

            if (isError) {
                console.log('validation error');
            }

            if (isSuccess) {
                console.log('validation success');
            }
        }, 0);
    };

    render() {
        const { field, ...otherProps } = this.props;

        return (
            <input
                className="floating-field"
                type="text"
                {...field}
                {...otherProps}
                onBlur={this.handleBlur}
            />
        );
    }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

outaTiME picture outaTiME  路  3Comments

pmonty picture pmonty  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments

jeffbski picture jeffbski  路  3Comments

najisawas picture najisawas  路  3Comments