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

Enhance FieldStore to Return Multiple Errors per Field #169

Open
Toeler opened this issue Jan 11, 2024 · 2 comments
Open

Enhance FieldStore to Return Multiple Errors per Field #169

Toeler opened this issue Jan 11, 2024 · 2 comments
Assignees
Labels
enhancement New feature or request

Comments

@Toeler
Copy link

Toeler commented Jan 11, 2024

I'm currently working with Valibot and Modular Forms, where the Field component's children prop provides a FieldStore. This store includes an error: string property. However, this implementation seems limited as a field might have multiple validation errors, but FieldStore only returns the first error encountered.

This limitation requires additional logic on my end. To display all errors, I need to call getValues and then use safeParse from Valibot, which is not ideal for development experience. I initially thought getErrors could be a solution, but it also returns only the first error for each field.

For an improved DX, I propose enhancing FieldStore to include an errors: string[] | undefined property. This change would allow developers to easily access and display all relevant errors for a field.

Could this enhancement be considered for a future update?

@fabian-hiller
Copy link
Owner

This behavior is intentional and probably expected in most cases. However, I agree that this should be configurable or we should switch to your approach in the long run.

For now, there is a workaround. You can copy the code from the Valibot adpater and set abortPipeEarly to false. You also need to change the logic so that fields with the same path are not overwritten, but the strings are concatenated.

@fabian-hiller fabian-hiller self-assigned this Jan 12, 2024
@fabian-hiller fabian-hiller added the enhancement New feature or request label Jan 12, 2024
@Toeler
Copy link
Author

Toeler commented Jan 12, 2024

Thank you. I didn't consider just rewriting valiForm. Indeed, that gets most of the way there although as you said, you would need to concatenate the errors rather than returning them as an array.

This is a hacked attempt as making use of domain knowledge that the string is actually a string[] | undefined.

import { $, implicit$FirstArg, type QRL } from '@builder.io/qwik';
import type {
	FieldValues,
	FormErrors,
	MaybeFunction,
	PartialValues,
	ValidateForm,
} from '@modular-forms/qwik';
import type { BaseSchema, BaseSchemaAsync } from 'valibot';

/**
 * See {@link valiFormWithErrors$}
 */
export function valiFormWithErrorsQrl<TFieldValues extends FieldValues>(
	schema: QRL<MaybeFunction<BaseSchema<TFieldValues, any> | BaseSchemaAsync<TFieldValues, any>>>,
): QRL<ValidateForm<TFieldValues>> {
	return $(async (values: PartialValues<TFieldValues>) => {
		const resolvedSchema = await schema.resolve();
		const result = await (typeof resolvedSchema === 'function'
			? resolvedSchema()
			: resolvedSchema
		)._parse(values, { abortPipeEarly: false });
		console.log('vali', result);
		return result.issues
			? result.issues.reduce<FormErrors<TFieldValues>>((errors, issue) => {
					const key = issue.path!.map(({ key }) => key).join('.') as keyof FormErrors<TFieldValues>;
					const fieldErrors: string[] = (errors[key] as unknown as string[] | undefined) ?? [];
					fieldErrors.push(issue.message);

					errors[key] = fieldErrors as unknown as string; // Intentionally hide an array as a string

					console.log(key, 'issues', errors);
					return errors;
			  }, {})
			: ({} as FormErrors<TFieldValues>);
	});
}

/**
 * Creates a validation functions that parses the Valibot schema of a form.
 *
 * @param schema A Valibot schema.
 *
 * @returns A validation function.
 */
export const valiFormWithErrors$ = implicit$FirstArg(valiFormWithErrorsQrl);

It works, but obviously isn't something worth proceeding with.

My use case is a user registration form with an Email and Password inputs.
The email field doesn't really matter, as that just has a single validator.
But the password field has a list of constraints, and under the field it shows these constraints and as the user types, each constraint ticks as it passes.

The two requirements is:

  1. Like How to validate a specific field when input changes (Solid) #116 it would be good to validate each of these at different points (email on blur, but password on input)
  2. This issue, whereby a field reports all of the errors so that I can compare those against the initial constraints that I calculate (by running a validation against the empty input and getting all of the issues)

I will continue to watch this space for cleaner implementations, thanks.

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

No branches or pull requests

2 participants