Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dirty check doesn't work when resetForm values contains optional field #4966

Open
3 of 5 tasks
sander96 opened this issue Dec 22, 2024 · 1 comment
Open
3 of 5 tasks

Comments

@sander96
Copy link

sander96 commented Dec 22, 2024

What happened?

Consider a use case where user types something in the form and then moves to some other page but forgets to save. In this case it would be nice to show a confirmation dialog to the user to verify if they want to leave the page without saving.

In order to do this, I'm using meta object dirty value to check if at least one field's value has been changed. When the user lands on the page then initial data is fetched from the backend server. I'm using resetForm to update the values and reset meta state just like it's described in here https://vee-validate.logaretm.com/v4/guide/composition-api/handling-forms/#setting-initial-values-asynchronously. This works for most fields but sometimes there's no "dirty check" for some other fields.

Reproduction steps

Open stackblitz demo link

  1. Type something in the 3rd field. - "Dirty check" works as expected.
  2. Press Reset button. - This mimics API request, sets values and resets meta state.
  3. Type something in the 3rd field. - "Dirty check" doesn't work at all.

I've observed that when field1 is undefined then the last field's "dirty check" doesn't work. When field1 is something else than undefined then "dirty check" works for all fields. I've also observed that when the order of formSchema's field2 and field3 is changed, then field2 dirty check doesn't work anymore but field3 dirty check works.

Version

Vue.js 3.x and vee-validate 4.x

What browsers are you seeing the problem on?

  • Firefox
  • Chrome
  • Safari
  • Microsoft Edge

Relevant log output

No response

Demo link

https://stackblitz.com/edit/vitejs-vite-id7xmdvf?file=src%2FApp.vue

Code of Conduct

@vonBrax
Copy link

vonBrax commented Jan 9, 2025

I just stumbled upon this exact same issue today and I spent a few hours unsuccessfully trying to reproduce it until I found this issue, so thank you @sander96 for the demo link.

I have exactly the same use case as the author, which is a schema with some optional fields and async data that is set using resetForm, which caused the dirty check to stop working.

Looking at the source code, the problem seems to be on this line inside the isEqual function:

for (i = length; i-- !== 0; ) {

Here, the loop index i is set to the value of length, which represents the count of all the object keys that have have a defined value.

The problem is that this logic leaves out of the comparison object entries with a proper defined value.

Using the linked demo example, after pressing reset, both objects will have the keys field1, field2, field3, and field1 is the one with an undefined value. Here length == 2, since field1 has an undefined value, so the loop compares keys at index 1 (field2) and index 0 (field1), leaving field3 out of the comparison, thus stating that the objects are equal, regardless of the value in field3.

I managed to fix the issue locally for me by replacing that loop with a normal loop reiterating again all the keys in object a (assuming that at this point both objects will have exactly the same keys, which seems to be true):

for (i = 0; i < keys.length; i++) {
  const key = keys[i];
  if (!isEqual(a[key], b[key])) return false;
}

I could open a PR if that's an acceptable solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants