Skip to content

Be able to setup a field level validation schema #25

Description

@outerlook

Description

Hi! It would be nice to set some field level validation.

Example

My example is a multi-step form that shares the same

element. This form asks for phone, name and email.

HTML
 STEP 1
<form>
	<input name='name'>
	<button type='submit'/>
</form>

 STEP 2
<form>
	<input name='phone'>
	<button type='submit'/>
</form>

STEP 3
<form>
	<input name='email'>
	<button type='submit'/>
</form>

I use zod for validating things.

And I'm using the following schema:

### Schema
const validationSchema = z.object({
	name: z.string().nonempty(),
	phone: phoneRegexValidation,
	email: emailValidation
})

Example's issue

Every step is required. But I can't use like that. If all of them are required for submitting, I can't use the button as a submit button for controlling my form. And I do have some clear options:

  • Handle only the last button as submittable, control my "steps" out of onSubmit (a bit boilerplatey)
  • Separate into 3 forms, one with each validation (less svelte composable components power)

There is an option I used on react, using the library react-hook-form

  • dynamically setup my validationSchema when "step" changed
### Schema
const validationSchema = step => z.object({
	name: z.string().nonempty(),
	phone: step > 0 ? phoneRegexValidation : optional,
	email: ztep > 1 ? emailValidation : optional
})
### Creating form context
const { form } = createFormContext({
		validateSchema: validationSchema(step),
		onSubmit: values => {
			if (!isLastStep) step++;
			else submitToServer(values)
		}
	})

But it doesn't seems to work (it could be another issue if I did it right, but that's not the main request here)

Svelte-action

I've being trying to create an svelte action to solve that:

### Implementation
export const validate = (
	node: HTMLInputElement,
	{ schema }: { schema: z.Schema<any> }
) => {
	const listener = (ev: Event) => {
		try {
			schema.parse(node.value)
		} catch (e) {
			ev.preventDefault();
			ev.stopPropagation();
			ev.stopImmediatePropagation();
			const error = e as z.ZodError<any>
			node.setCustomValidity(error.message)
		}
	}
	node.form?.addEventListener('submit', listener)

	return {
		destroy: () => {
			node.form?.removeEventListener('submit', listener)
		}
	}
}
### Usage
	<input
		use:validate={nameValidation}
		name="name"
	/>

But I'm having no success on that. It isn't preventing form onSubmit from being executed. I don't know how to achieve that outside felte.

Further comments

The library I mentioned (react-hook-form) uses a different and less html native for subscribing new fields that can validate at this level.

RHF validation docs

I mention them only for bringing examples of libraries that have this kind of field-level API (and are choosing to continue supporting it).

Another benefit of solving it would be composability problem. A form would not need to know every field that are inside them for validating purposes.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfelteRelated to main felte package

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions