Git Product home page Git Product logo

Comments (16)

jaredpalmer avatar jaredpalmer commented on May 5, 2024 15

Yes, you can create a mapPropsToValues function that would flatten the array and prefix/suffix each item.

const withFormik = Formik(
  ...
  mapPropsToValues: ({id, email, pets}) => ({
      id,
      email,
      ...(pets.reduce((accum, current, index) => Object.assign(accum, {
        [`pet_type_{index}`]: current.type,
        [`pet_name_{index}`]: current.name,
      }), {})
    })
  ...
)

This results in props.values that's equivalent to:

{
   id: string,
   email: string,
   pet_type_1: string,
   pet_name_1: string,
   pet_type_2: string,
   pet_name_2: string,
   ...
   pet_type_n: string,
   pet_name_n: string,
}

There are many ways to then display the pets. Using Object.keys and filter what I usually use in this situation. However, it really depends on your requirements. In the case of arbitrarily adding pets, you'll need to use props.setValues which allows you to declaratively call setState on just the key of Formik.state.values. This will modify props.values. If you need to rearrange or delete pets arbitrarily, you would not use the pets array index, but rather a uuid to uniquely identify each pet in the flattened state tree. Anyways, here's the simplest case (when the number of pets doesn't change).

// example of a form with a nested array that doesn't change size
const myForm = ({  values, handleSubmit, handleChange }) => (
  <form onSubmit={handleSubmit}>
    <input type="email" onChange={handleChange} id="email" />
    {Object.key(values).filter(v => v.startsWith('pet')).map((pet, i) => {
      <span>
        <input type="text" id={`pet_type_${i}`} value={values[`pet_type_${i}`]} onChange={handleChange} />
        <input type="text" id={`pet_name_${i}`} value={values[`pet_name_${i}`]} onChange={handleChange} />
      </span>
    })}
    <button type="submit">Submit</button>
  </form>
)

Hope that helps.

from formik.

eonwhite avatar eonwhite commented on May 5, 2024 14

@bitstrider @jaredpalmer

While you can take the above approach if you want, it's worth noting you're not required to flatten the values out. Formik will work fine with complex nested data structures within values -- you just have to handle them in your render and handlers. Flattening is useful when using regular HTML inputs, but you can always design your own components which deal with whatever data structures you want.

What I would probably do, if your API is taking an arbitrary number of pets, is build a controlled component called PetsInput that takes your nested array and an value prop, and an onChange callback that uses the handleChangeValue signature. You could design PetsInput as you wish, including add/delete/reorder controls if you wanted, all contained within that reusable component.

Then from your Formik form render you would just do something like:

<label>Pets</label>
<PetsInput id="pets" value={props.values.pets} onChange={props.handleChangeValue} />

from formik.

ronyfhebrian avatar ronyfhebrian commented on May 5, 2024 13

What about arrays with useFormik?
I have already used useFormik and now kinda confused of how to make arrays of components from initialValues, the values are updating but the component doesn't.
Please help

from formik.

bzuker avatar bzuker commented on May 5, 2024 9

how would I use the handleChangeValue to update the pet[0].name value with the approach @eonwhite
suggested?

I can't seem to find a way to update a particular object in an array.

from formik.

adamduncan avatar adamduncan commented on May 5, 2024 7

Hey @davidhernon - could you please elaborate on using Yup's lazy method in conjunction with Formik's validationSchema to produce validation rules for dynamically added fields?

from formik.

etaheri avatar etaheri commented on May 5, 2024 6

For anyone ending up here. Formic has a <FieldArray /> component that solves this! FieldArray Docs 😊

from formik.

davidhernon avatar davidhernon commented on May 5, 2024 3

@dannief You can use Yups lazy function in order to create a schema at validation time.

Using this allowed me to add validation schema for dynamically created inputs.

from formik.

jaredpalmer avatar jaredpalmer commented on May 5, 2024

Note you would use the same .reduce method trick to create a properly keyed validationSchema and mapValuesToPayload, respectively

from formik.

jaredpalmer avatar jaredpalmer commented on May 5, 2024

@bitstrider agree with @eonwhite 100%.

from formik.

json2d avatar json2d commented on May 5, 2024

@jaredpalmer @eonwhite thanks these solutions work, and perhaps should get included in the README since array of fields is a common use case for forms IMO (esp say on admin panels).

I think mapPropsToValue and mapValuesToPayload adds an interesting degree of freedom, but in general I would prob end up avoid having to manage multiple data shapes.

from formik.

jaredpalmer avatar jaredpalmer commented on May 5, 2024

Formik will pass all props that are not function into values automatically. If you don’t specify mapValuesToPayload, all values become payload by default. These methods are meant to help organize your code. They make refactoring much easier

from formik.

dannief avatar dannief commented on May 5, 2024

@jaredpalmer

Note you would use the same .reduce method trick to create a properly keyed validationSchema and mapValuesToPayload, respectively

Am I right in assuming that if I wanted to dynamically add inputs that should be validated, then the implementation that you described would not work, since the yup schema is set within the formik config and cannot be updated dynamically?

Are there any plans to better support this scenario? I am thinking that without requiring the developer to manually flatten the values and schema, if we provide a mapping such as pets[1].type , it could just work and easily support dynamic forms. I am currently using the form library by the author of yup called react-formal and this is the approach used. I like HOC and flexible approach of formik though and wanted to evaluate it for another project. It is not so flexible in this scenario so it's stopping me from going forward with it right now. But great job by the way.

from formik.

dannief avatar dannief commented on May 5, 2024

@davidhernon Thanks for the tip. Will check out the lazy function

from formik.

Kaijun avatar Kaijun commented on May 5, 2024

@jaredpalmer I think there could be some kind of implementations like the <Filed>, we could add a new HoC <Fields /> to automate mapping array to fields item_1, item_2 ... and assembling them back to array while calling onSubmit

from formik.

Ranthalion avatar Ranthalion commented on May 5, 2024

For anyone ending up here. Formic has a <FieldArray /> component that solves this! FieldArray Docs 😊

Field Array docs moved to https://jaredpalmer.com/formik/docs/api/fieldarray

from formik.

JosefHobler avatar JosefHobler commented on May 5, 2024

I used useFormik and made it work like this

schema:
[ { value: 48 }, { value: 48 } ]

`
<input
type='number'
placeholder={intl.formatMessage({ id: "APP.MODAL.FEEDBACK.INPUT.NAME" })}
autoComplete='off'
{...formik.getFieldProps(index + ".value")}
className={clsx(
'form-control bg-transparent',
{
'is-invalid': formik.touched[index]?.value && formik.errors[index]?.value,
},
{
'is-valid': formik.touched[index]?.value && !formik.errors[index]?.value,
}
)}
/>
{formik.touched[index]?.value && formik.errors[index]?.value && (



{formik.errors[index]?.value}


)}

from formik.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.