final-form / final-form

🏁 Framework agnostic, high performance, subscription-based form state management

Home Page:https://final-form.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Dirty and modified states are not correct in Wizard form

sedx opened this issue · comments

Are you submitting a bug report or a feature request?

bug report

What is the current behavior?

  1. Change fisrt name
  2. Click Next
  3. Check the dirty state and modified fields
  4. Pick color
  5. Click Next
  6. Check the dirty state and modified fields

What is the expected behavior?

  • On step 3 dirty state of form should be true, because initial values are not match to current values and modified fields should contain firstName key
  • On step 6 dirty state should be true too and modified fields should contain firstName and favoriteColor keys (because they are was modified)

Sandbox Link

https://codesandbox.io/s/wizard-example-cpset?fontsize=14

What's your environment?

react-final-form 4.18.5

Other information

In my project I have complicated form, that split to multiple tabs (so form looks like wizard).
But user can save from data from any step, not from the last. Save button enabled only when form is in dirty state.
Tabs are lazy loaded and when we change tab current <Field /> components are unmounted.

When I change some values in form on tab A - form becomes dirty, when I goes to tab B changed fields are unmounted, changed values still stored in value (it is ok), but dirty state now are false (it's looks like not ok).

Actually form is dirty, because my initial value is not match the current form value.
Also list of modified fields are changed too (it's drops fields from A's tab). It's not represent actual diff from initial and current value.

Yes, as I told, when field unmount new form's state calculated and forms global dirty and modified based on list of current registered fields
For dirty:

final-form/src/FinalForm.js

Lines 516 to 542 in a95948a

// calculate dirty/pristine
let foundDirty = false
const dirtyFields = safeFieldKeys.reduce((result, key) => {
const dirty = !safeFields[key].isEqual(
getIn(formState.values, key),
getIn(formState.initialValues || {}, key)
)
if (dirty) {
foundDirty = true
result[key] = true
}
return result
}, {})
const dirtyFieldsSinceLastSubmit = safeFieldKeys.reduce((result, key) => {
// istanbul ignore next
const nonNullLastSubmittedValues = formState.lastSubmittedValues || {} // || {} is for flow, but causes branch coverage complaint
if (
!safeFields[key].isEqual(
getIn(formState.values, key),
getIn(nonNullLastSubmittedValues, key)
)
) {
result[key] = true
}
return result
}, {})
formState.pristine = !foundDirty

For modified, touched and visited:

final-form/src/FinalForm.js

Lines 554 to 562 in a95948a

const { modified, touched, visited } = safeFieldKeys.reduce(
(result, key) => {
result.modified[key] = safeFields[key].modified
result.touched[key] = safeFields[key].touched
result.visited[key] = safeFields[key].visited
return result
},
{ modified: {}, touched: {}, visited: {} }
)

I can create MR to keep global dirty state and list of modified unmounted fields.

There is two way:

  1. Fix it and reflect actual form state out of box (look like breaking changes, or may be reason for unexpected behaviour in other projects)
  2. Add keepFormStateOnFieldUnmount to config and dependent on values of this attribute keep current behaviour, or keep actual form state.

@erikras What do you think?

I think for final-form config name should be keepFormStateOnFieldUnregister (there is not 'unmount' for fields in final-form)

keepFormStateOnFieldUnmount will be props for react-final-form (where is fields unmounted)

As I understand nobody cares about this issue?

@sedx do you have any updates on this issue?

@aleshanter No 😅 I have no answer about which way to choose for fix, so I did not start with changes. On project I was check initial values and current state for diff (I supose)

I checked codesandbox with latest version - issue is still here.