ealush / vest

Vest ✅ Declarative validations framework
https://vestjs.dev/
MIT License
2.56k stars 84 forks source link

Validation errors only after "touched" #809

Closed roblevintennis closed 2 years ago

roblevintennis commented 2 years ago

First of all, @ealush thank you for this marvelous form validation library. I really like the creative solution to use the same DSL we use for testing for validation. I also love that it's framework-agnostic. I also love that it's an importable small script.

I'm building some examples on my blog on how to incorporate AgnosticUI http://agnosticui.com/ and use Vest for the validation. It's going quite well and I'm close to having my first example complete!

There is one thing…

Overview

Many form validation libraries or engines hold the notion of a field being "touched" when it's been interacted with and then blurred.

I searched the documentation site for touched and only found one reference here: https://vestjs.dev/docs/writing_your_suite/optional_fields#advanced-usage---supplying-custom-omission-function

But I still don't see or perhaps understand how this is achieved in Vest.

Reproductions

The default examples appear to eagerly report validation errors as I've described. Below is a screen grab, but also here are the repro steps:

  1. visited username field
  2. entered a single character

Result: Error messages hints displayed Expected: There should be no error message hints displayed until I blur out of said field

  1. visited the password field
  2. entered first character

Result: Error messages hints displayed Expected: There should be no error message hints displayed until I blur out of said field

image

Remarks

I think in UX circles this sort of thing is called "shouting". I would prefer if my password field validity is only shown once I've interacted with the field and then navigated out of it (e.g. touched or blurred the field if you will). Is this achievable and documented and I just missed it?

ealush commented 2 years ago

Hey @roblevintennis, thank you for your feedback, I always love learning about new integrations with Vest.

I am not near a computer, and it might take some time for me to give a more detailed reply. Nevertheless, I do intend to give a more in-depth reply.

I'll try to briefly describe the core concepts:

The reason Vest does not have the notion of touched is that vest is not a UI framework, meaning it knows nothing about the UI state. This means it cannot know about the interaction with the inputs, and really, vest does not even have to retain a 1 to 1 relationship between inputs and tests. Instead, all Vest cares for are validation states: tested, failing, valid, pending, omitted, skipped.

In most cases, touched is correlary to tested, meaning - trigerring validation of a certain field on blur rather than on should be sufficient.

To do that, use only with the name of the touched field. You can look up the only function in the api reference. https://vestjs.dev/docs/api_reference

I did not yet read your code, or look deeper into your implementation, I will do that when I'm near a computer, but in the meantime I hope this at least somewhat helps.

roblevintennis commented 2 years ago

Thanks @ealush that's very helpful indeed!

The suite.js code is mostly a copy of your example which already does the only(currentField) anyway so we're good there -- now that I properly understand the "concerns" being managed by Vest I think my issue is resolved.

It was of course very easy to add the following in my code which results in the suite only getting called once a field has been touched per your recommendation:

image

  let touched = {
    tos: false,
    username: false,
    password: false,
    confirm: false,
  };

  const validate = fieldName => {
    if (touched[fieldName]) {
      result = suite(formState, fieldName);
      result.done(res => {
        usernamePending = false;
        result = res;
        // console.log('Vent Result: ', { result })
      });
    }
  }
  /**
   * Blurring field makes it "touched" and candidate for validation
   */
  const handleBlur = name => {
    if (touched[name] === false) {
      touched[name] = true;
      // First time this field is considered "touched" e.g. user just tab'd or clicked out
      // of the field. As such, we now need to validate said field for the first time!
      validate(name);
    }
  }
 // ... code omitted for brevity but we listen for change events and potentially call validate
// from other places too. But only evaluated if we've set touched.FIELDNAME to true.

My spot checks confirm this is working. Thanks again! I'll go ahead and close this issue out 👍

ealush commented 2 years ago

@roblevintennis Awesome! Very happy to hear that it worked as expected.

Also, just taken a look at AgnosticUI - that's some impressive project you got going there. I am definitely going to keep an eye on it!

roblevintennis commented 2 years ago

Thanks @ealush I really appreciate it from you 🙂

I will ping you but I have a Svelte based blog where I'm starting to dig food agnostic-svelte and the very first example I thought of was using Vest. I saw your presentation at Svelte conference (I think or maybe Vue) but was very impressed by the idea and that it's not tied to any framework. So I had to see how they work together and I am NOT disappointed!

Again I will ping you once I have something to show. Thanks for building such a nice validation lib!