Formik: Feature & Question: Hook for manual transformations

Created on 2 May 2018  Â·  16Comments  Â·  Source: formium/formik

Feature & Question?

Feature/Question: an way/hook where to do yup casting /manually transformations.
lets say input text to uppercase.

Current Behavior

No option or, onChange={(name, value) => setFieldValue(name, value.toUpperCase() <-----here the transformation )} but that feels not right putting business logic there.

Desired Behavior

to be discussed, any hook between setting values and triggering validate in withformik function.

Suggested Solutions

na

Additional Information

see yup transform https://github.com/jquense/yup#mixedtransformcurrentvalue-any-originalvalue-any--any-schema example

var schema = yup.string().transform(function(currentValue, originalvalue){
  return this.isType(value) && value !== null
    ? value.toUpperCase()
    : value
});

schema.cast('jimmy') //=> 'JIMMY'


  • Formik Version: v1.0.0-alpha.6
  • React Version: na
  • TypeScript Version: na
  • CodeSandbox Link: na
  • OS: na
  • Node Version: na
  • Package Manager and Version: na
stale

Most helpful comment

I was looking for a hook like this, too, and ended up just doing a simple String.toLowerCase before manually setting the fieldValue. For example, within a <Field> component, implement your own onChange:

onChange={e => {
    let value = e.target.value || "";
    value = value.toLowerCase().trim();
    setFieldValue(field.name, value);
}}

All 16 comments

Does anyone from contributors team see this issue?

@jaredpalmer Hi, can you inform, does this issue will be resolved in v1?

I think there will be escape hatches in v1 for transform and maybe parse. However, I am not certain that _more_ Yup integration is coming/needed. The defaults seem to cover most use cases. Advanced yup usage like cast and transform can be utilized in a custom validate prop and using the exported transformYupToFormErrors function. This last bit needs more documentation. In fact, we've discussed internally about deprecating the validationSchema prop from formik core and creating a separate formik-schema package with this feature + necessary helper functions. Having to manage 2 ways to do validation makes the codebase much harder to maintain

Yup schemas useful because it has some default vaildation features like require, min, max, and much more. You can add some other quick validation with test if you need it.
And if you want rid of yup, so formik users should do a lot of manual work to validate simple form.

Hola! So here's the deal, between open source and my day job and life and what not, I have a lot to manage, so I use a GitHub bot to automate a few things here and there. This particular GitHub bot is going to mark this as stale because it has not had recent activity for a while. It will be closed if no further activity occurs in a few days. Do not take this personally--seriously--this is a completely automated action. If this is a mistake, just make a comment, DM me, send a carrier pidgeon, or a smoke signal.

ProBot automatically closed this due to inactivity. Holler if this is a mistake, and we'll re-open it.

@jaredpalmer Reopen, please.

I'd vote to reopen this as well. I'm trying to submit string values (via a <select>) '1' or '0' to a yup-validated backend where strict has to be true (so no casting to Boolean possible — the value has to be a Boolean before it reaches the server) and I can't figure out how to do it in a non-ugly way.

It's a pity, but this issue nobody see, or doesn't want to see.

It should be straight forward to implement a manual transformValues function before data is processed by validation. Unfortunately, it isn't because of the (too) tight coupling with yup. I thought I could work around this by implementing the validate function, transforming the data and calling a yup schema until I realized that yup is a fail fast solution. It will not process the schema after a value fails. Formik has a function that processes all the values, however, it's not exposed on the api.

My suggestion would be to change the validationSchema prop to pass the data, allowing you to process it and return schema.validate(data)

@jaredpalmer Reopen issue, please!

I was looking for a hook like this, too, and ended up just doing a simple String.toLowerCase before manually setting the fieldValue. For example, within a <Field> component, implement your own onChange:

onChange={e => {
    let value = e.target.value || "";
    value = value.toLowerCase().trim();
    setFieldValue(field.name, value);
}}

@Neilpoulin thanks for the sample code, was looking for a clean way to do exactly the same thing, unfortunately Formik does not provide any hooks for this. Seems to me this could be implemented in the <Field> component without too much hassle as it already provides the onChange method to the underlying DOM field...

@jaredpalmer this should probably be an open issue unless #728 is a won't merge

What's wrong with @Neilpoulin solution? IMO there isn't a need to add this kind of functionality directly into Formik.

We have moved from redux-form to Formik and really needed the normalize and format functionality that redux-form provided. To do this we wrote our own <Field> that takes format and normalize as props. It also accepts an onChange prop for situations like where a SelectField needs to hide other fields based on its value. So I think what we've done is similar to what @Neilpoulin suggested where we hook into field.onChange() and normalize it if needed.

const Field = React.memo(({ component: Component, name, format, normalize, useContext, onChange, ...otherProps }) => (
  <FieldSetConsumer>
    {context => (
      <FastField name={formatFieldName(useContext ? context : '', name)}>
        {({ field, form }) => {
          const fieldOnChange = field.onChange;
          field.onChange = event => {
            const newValue = normalize ? normalize(event.target.value) : event.target.value;
            event.target.value = newValue;
            const oldValue = field.value;

            fieldOnChange(event);
            if (onChange) {
              onChange({ event, field, form, newValue, oldValue });
            }
          };

          return (
            <Component
              field={{
                ...field,
                value: format ? format(field.value) : field.value
              }}
              form={form}
              {...otherProps}
            />
          );
        }}
      </FastField>
    )}
  </FieldSetConsumer>
));
Was this page helpful?
0 / 5 - 0 ratings