Formik: setTouched doesn't do anything on fields inside field arrays

Created on 5 Mar 2020  路  7Comments  路  Source: formium/formik

馃悰 Bug report

Current Behavior

I currently have a form with this structure :

{
  color: 'red',
  extraColors:
    [ 
      { name: 'blue', transparency: 80, code: 8281 }, 
      { name: 'orange', transparency: 30, code: 8321 } 
    ]
}

and I use yup validation to validate every field here, no problem with that. However, I do not display errors until a OK button is clicked, so the validation doesn't run on blur or on change.

To display errors once the validation has run, I have to set the whole extraColor field as touched (field name would be extraColors.1). For now, I have to call setTouched(true) for every field in the extraColors.1 field, which is cumbersome. Those fields are extraColors.1.name, extraColors.1.transparency and extraColors.1.code. That results in this kind of code:

const [name, nameMeta, nameHelpers] = useField(
    `extraColors.1.name`
  )
  const [transparency, transparencyMeta, transparencyHelpers] = useField(
    `extraColors.1.transparency`
  )
  const [code, codeMeta, codeHelpers] = useField(
    `extraColors.1.code`
  )

nameHelpers.setTouched(true)
transparencyHelpers.setTouched(true)
codeHelpers.setTouched(true)

Expected behavior

const [extraColor, extraColorMeta, extraColorHelpers] = useField(
    `extraColors.1`
 )

extraColorHelpers.setTouched(true)

// all sub fields would be set as touched, displaying each field's errors if there is.

Suggested solution(s)

Allow all sub-fields to be touched as well.

Your environment

| Software | Version(s) |
| ---------------- | ---------- |
| Formik | 2.1.4
| React | 16.8.1
| TypeScript | Not used
| Browser | Chrome
| npm/Yarn | npm version 6.13.7
| Operating System | Mac OS X

stale

Most helpful comment

What about the Formik#setTouched function? Would something like the following solve your problem?

form.setTouched(
  Object.assign(form.touched, {
    extraColors: [form.values["extraColors"].map(() => ({ name: true, transparency: true, code: true }))]
  })
);

All 7 comments

What about the Formik#setTouched function? Would something like the following solve your problem?

form.setTouched(
  Object.assign(form.touched, {
    extraColors: [form.values["extraColors"].map(() => ({ name: true, transparency: true, code: true }))]
  })
);

@fxh1357 Your solution works for setting the touched properties for an array of objects.

But my problem is that I still have that async issue with setTouch when using it inside onChange.

@arvinsim Could you explain that in further detail? Which 'async issue' do you mean?

@fxh1357 I think it was commented elsewhere. But essentially, the issue was that setTouched is async. When I run an operation that computes something from the values, it uses the previous values instead of the new one.

@arvinsim Have a look at Dependent Fields. You are constrained by the React render cycle. If you want to use changed state for updated calculations you have to wait for it using e.g. useEffect()

@fxh1357 I copied the code from that link. It works great except that it doesn't work on nested array of objects field due to touched object not being defined properly. See this codesandbox

I tried using your solution but I don't know where to put your setTouched code. Is it supposed to be in the nested array of objects field onChange?

@arvinsim Mhh, I just tried to reproduce your originl issue and had to realize that it's gone. It seems as if #2265 fixed your problem, doesn't it?!

Regarding your most recent example - I think it's 'handleBlur' not 'onBlur'

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaredpalmer picture jaredpalmer  路  3Comments

ancashoria picture ancashoria  路  3Comments

green-pickle picture green-pickle  路  3Comments

sibelius picture sibelius  路  3Comments

dearcodes picture dearcodes  路  3Comments