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

$rewardEarly stops working if a previous field is invalid #1237

Open
renatodeleao opened this issue Apr 5, 2024 · 1 comment · May be fixed by #1240
Open

$rewardEarly stops working if a previous field is invalid #1237

renatodeleao opened this issue Apr 5, 2024 · 1 comment · May be fixed by #1240

Comments

@renatodeleao
Copy link

renatodeleao commented Apr 5, 2024

Describe the bug
$rewardEarly mode states that validators only run after $commit has been called, usually onBlur. I've noticed, by chance, if I have multiple fields, and the first one is invalid after commit, the second field after the first blur/commit will start validating immediately on $model change not when $commit is called, effectively not using $rewardEarly mode.

Warning

EDIT: the feature is broken without the need for this setup at vue@3.4.x which optimized computed recalculations with more agressive caching. I've discovered by accident on my project because this repo is still on 3.2.x https://stackblitz.com/edit/vitejs-vite-gnfzbf?file=src%2FAppForm.vue

Reproduction URL
Vuelidate 2 - Composition API + Vue 3

To Reproduce

  1. Fill/empty the "name" field, you'll see that validation only triggers when blurring, which is the normal $rewardEarly thing
  2. Now trigger that first field error, by blurring it blank
  3. Go to the "Name sibling field" and blur it to $commit: it doesn't matter if filled/valid or invalid the bug will still occur anyways
  4. Now focus back on it: you'll notice that from this point on validation is now triggering immediately when you empty the field not when blurring 🐛

Expected behavior
The validation state from sibling of a "B" field should not affect "B" validation.

Video

rewardEarlyBug.mp4

Additional Info

  1. if you correct the first field, then the sibling field will start working as expected 🤷
  2. Order seems to matter, if you try do this in the opposite way, as in blurring second field first and then go to the first, the error does not occur. I've made a demo with 3 fields and we can notice that it's the previous sibling state that affects all next siblings .
renatodeleao added a commit to Crowd9/vuelidate that referenced this issue Apr 9, 2024
renatodeleao added a commit to Crowd9/vuelidate that referenced this issue Apr 9, 2024
…cenarions

- exracted invalid computation side-effect out of result.$invalid computation to keep it pure
- watch that value to perform the side-effect on $lastInvalidState
- reuse the computed value inside result.$invalid
renatodeleao added a commit to renatodeleao/vuelidate that referenced this issue Apr 14, 2024
renatodeleao added a commit to renatodeleao/vuelidate that referenced this issue Apr 14, 2024
closes vuelidate#1237

1. Moved $lastInvalid assignment from the results.$invalid computed because
   computed props should be side-effect free.
2. Added a watcher to update $lastCommittedOn because otherwise the $commit()
   would turn it $lastInvalidState to true if the current input was !invalid.
   With the right conditions, changing recomputed the invalid state to false
   and the validation
   Write me better
3. this is required for async validators to work in this mode, otherwise last
   invalid state will be flipped to false since sync validators run first and
   turn invalid to false "before" pending is set to true and it will prevent
   them from running (Guessing)
renatodeleao added a commit to renatodeleao/vuelidate that referenced this issue Apr 14, 2024
closes vuelidate#1237

1. Moved $lastInvalid assignment from the results.$invalid computed
   because computed props should be side-effect free.
2. Added $lastCommittedOn as a watch source because 3.4.x vue will cache
   computed more aggressively and $lastInvalidState would be out of sync
   in the "commit() when valid" scenario:
   - commit() sets $lastInvalidState to true
   - validators run and return invalid as false
   - result.$invalid is already false, so it will not recompute (cached)
   - the watcher will not be triggered because $result.$invalid dep did
     not change.
   - last $invalidState is not set to false, and thus $model change
     triggers validators to run.
   I don't know if it's out-of-scope of this PR to update vue, but 3.4.x
   brought many changes to computed optimization which vuelidate relies on
   heavily and it's the future.
3. flush "post" is required for async validators to work in this mode, otherwise
   last invalid state will be flipped to false since sync validators run first
   and turn invalid to false "before" pending is set to true and it will prevent
   them from running (Guessing). At least is required for 3.4.x and that's
   the version the majority should be using.
@renatodeleao renatodeleao linked a pull request Apr 14, 2024 that will close this issue
13 tasks
@renatodeleao
Copy link
Author

update: the feature is broken without the need for this scenario in "setup" vue@3.4.x

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

  1. Just commit (blur) the input with a valid result
  2. Go back and delete content and the validation triggers immediately (no commit).

#1240 fixes both scenarios here.

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

Successfully merging a pull request may close this issue.

1 participant