rvf icon indicating copy to clipboard operation
rvf copied to clipboard

[Bug]: formState.isDirty is still false after pushing into a field array

Open airjp73 opened this issue 8 months ago • 8 comments

Which packages are impacted?

  • [x] @rvf/react
  • [x] @rvf/react-router
  • [ ] @rvf/zod
  • [ ] @rvf/yup
  • [ ] zod-form-data

What version of these packages are you using?

  • @rvf/react 7.1.2

Please provide a link to a minimal reproduction of the issue.

https://codesandbox.io/p/sandbox/vzr6j9

Steps to Reproduce the Bug or Issue

In the codesandbox reproduction, click the Push button. The isDirty form state should switch to true, but it doesn't. You have to dirty the field itself first.

Expected behavior

The form itself should be dirty after modifying a field array, even if the fields inside the field array item aren't actually dirty.

Screenshots or Videos

No response

Platform

  • OS: Mac
  • Browser: Arc
  • Version: 1.91.0

Additional context

No response

airjp73 avatar Apr 25 '25 14:04 airjp73

Hello :),

I'm facing a similar issue on RVF 8. The form isDirty remains false after adding or deleting array items. Have you find a workaround?

bakura10 avatar Aug 26 '25 08:08 bakura10

Hello :),

I'm facing a similar issue on RVF 8. The form isDirty remains false after adding or deleting array items. Have you find a workaround?

Hi!

As a temporary workaround, you could update the dirty state manually: form.setDirty("myFieldArray", true). Not ideal, but gets the job done until the bug is fixed.

airjp73 avatar Aug 28 '25 14:08 airjp73

Thanks for the trick! This works but this is not optimal though. First you need to carry the form in the component (I am using the scope and field to only pass to components the fields they need, so I don't have access to the parent form). Secondly, as soon as you put it dirty, if the user reconfigure the array to the previous state it will stay dirty while the user might have revert to a non-dirty state.

bakura10 avatar Aug 29 '25 04:08 bakura10

First you need to carry the form in the component (I am using the scope and field to only pass to components the fields they need, so I don't have access to the parent form).

If you're passing a scope, you can do this to get access to the form api:

const formApi = useFormScope(myScope);

And all the helpers are scoped down to that part of the form. No need to pass a form-level api explicitly.

airjp73 avatar Sep 01 '25 21:09 airjp73

This is not working @airjp73 . While you can go down (so creating a scope from a form), you cannot revert back a scope to its original form (when you do so then the form become empty). Said otherwise this won't work:

// In parent component

<Foo scope={form.scope('foo')} />

// In foo.ts component:

const formApi = useFormScope(scope);
// formApi is not the same as the original form

bakura10 avatar Sep 02 '25 05:09 bakura10

you cannot revert back a scope to its original form

That's correct, but also isn't necessary. Here's an example of how this would be used to update the dirty state of the foo field:

const base = useForm(/* etc */);

const foo = useFormScope(base.scope('foo'));

// this
foo.setDirty(true);
// is equivalent to this
base.setDirty("foo", true);

Going back to the original field array use-case, you might do something like this:

const MyForm = () => {
  const form = useForm(/* etc */);
  return <MyArray scope={form.scope("myArray")} />
}

const MyArray = ({ scope }) => {
  const array = useFieldArray(scope);
  const formApi = useFormScope(scope);

  return (
    <ul>
      {array.map((key, item) => (
        <MyItem key={key} scope={item.scope()} />
      ))}
      <button
        type="button"
        onClick={() => {
          array.push("");
          formApi.setDirty(true);
        }}
      >
        Add item
      </button>
    </ul>
  );
}

airjp73 avatar Sep 02 '25 17:09 airjp73

For reference, this issue happens for all array methods (such as move, swap, remove) and not just push.

bakura10 avatar Sep 11 '25 06:09 bakura10

Just to comment back on this, the workaround, while working, is quite confusing. Having to deal with lot of different elements (a scope, a "field array", a "form scope"...) is confusing. I have a component when I have two scopes as a parameter, so I need to create two "fieldArray", two "formApi". I tried to check if I could fix the issue myself in the library as this makes RVF quite painful to use whenever array are involved (unfortunately, all my forms in this projects have forms) but for some strange reason I could not run the test suite (I have some errors that I could not understand).

bakura10 avatar Sep 15 '25 01:09 bakura10