ciscoheat / sveltekit-superforms

Making SvelteKit forms a pleasure to use!
https://superforms.rocks
MIT License
2.14k stars 64 forks source link

Client side validation upgrade #66

Closed ciscoheat closed 1 year ago

ciscoheat commented 1 year ago

Discussed in https://github.com/ciscoheat/sveltekit-superforms/discussions/45

Originally posted by **alesvaupotic** March 20, 2023 Hey! 0.6 is great improvement, love it. Question on client side validation: validation happens on submit, errors are set and with `defaultValidator: 'clear'` they go away as soon as input is correct. But, if I return to an already validated input and enter incorrect value, the error doesn't return until I submit the form again. I must be missing something here as revalidations don't run on input change from valid to error but they do run from error to valid?

The main issue

The problem with making validation work with a pattern like reward early, validate late is that Superforms aren't using any form events, it knows nothing about the form that you're using its store properties on. This is what makes it easy to use, but poses a problem when it comes to events like on:blur and on:input. Adding those events manually to every form field is not viable, so the next option would be to add those events to the form itself, using the bubbling phase to determine what happened.

This would have worked fine for top-level fields, but the data can be nested, so if you're outputting an array of tags:

{#each $form.user.tags as _, i}
  Name: <input bind:value={$form.user.tags[i]} />
{/each}

Then the input event don't know that the changed field is bound to $form.user.tags[i], which is what is needed to locate the correct validator, which could look like:

const { form } = superForm(page.data, {
  validators: {
    user: {
      tags: (tag) => tag.length < 1 ? 'Tag must have a name' : null
    }
  }
})

The $tainted store comes to mind, which accurately keeps track of each field that has changed. Maybe it can be used on each input/blur/etc event to diff its previous state, thereby determining which field(s) changed on each event.

Any ideas about this is appreciated!

ciscoheat commented 1 year ago

Got a nice suggestion on the discord to make a derived store that intersects $tainted and $errors. I wonder if this is enough...!

alesvaupotic commented 1 year ago

Validating data is only part of the process. We'll still need some piece of code to react to input losing focus if no data has changed, like tabbing away from an empty input. Intersecting $taintedand $errors is good approach, but additional store has to track touched inputs, to not show errors on inputs which user has not visited yet.

ciscoheat commented 1 year ago

Fixed now with v0.8! Announcement: https://github.com/ciscoheat/sveltekit-superforms/discussions/106