Open
Description
In a form with two inputs with multiple validations, error messages may fail to update, depending on the order in which the user edited the field values.
For example, in the form shown below, take the following actions:
- Without entering any text, click on "Post". The error messages "Foo text is blank." and "Bar text is blank." will appear.
- In the Foo input, type "a". The Foo error message will update to "Foo text is too short."
- In the Bar input, type "a". The Bar error message does not update.
The expectation is that both error messages should update.
Note that there is no difference between Foo and Bar; it is the order in which text is entered that determines which field will fail to update. For example, by swapping steps 2 and 3, the Bar error message will update correctly but the Foo error message will not.
Form code follows:
import { component$, isBrowser } from "@builder.io/qwik";
import { routeLoader$ } from "@builder.io/qwik-city";
import {
formAction$,
useForm,
valiForm$,
type InitialValues,
} from "@modular-forms/qwik";
import * as v from "valibot";
const FooBarSchema = v.object({
foo: v.pipe(
v.string(),
v.nonEmpty("Foo text is blank."),
v.minLength(2, "Foo text is too short."),
),
bar: v.pipe(
v.string(),
v.nonEmpty("Bar text is blank."),
v.minLength(2, "Bar text is too short."),
),
});
type FooBarForm = v.InferInput<typeof FooBarSchema>;
type SuccessData = { record: { id: number } };
export const useFooBarFormAction = formAction$<FooBarForm, SuccessData>(
(formData) => {
// HACK: https://github.com/QwikDev/qwik/issues/5160
if (isBrowser) {
throw new Error();
}
const { foo, bar } = formData;
const record = {
id: 1,
foo,
bar,
};
return {
status: "success",
data: { record },
};
},
valiForm$(FooBarSchema),
);
export const useFormLoader = routeLoader$<InitialValues<FooBarForm>>(() => ({
foo: "",
bar: "",
}));
export default component$(() => {
const [, { Form, Field }] = useForm({
loader: useFormLoader(),
action: useFooBarFormAction(),
validate: valiForm$(FooBarSchema),
});
return (
<Form>
<h1>Foo Bar Form</h1>
<Field name="foo">
{(field, props) => (
<>
<label for="foo">Foo</label>
<input {...props} id="foo" type="text" value={field.value} />
{field.error && <div class="error">{field.error}</div>}
</>
)}
</Field>
<Field name="bar">
{(field, props) => (
<>
<label for="bar">Bar</label>
<input {...props} id="bar" value={field.value} />
{field.error && <div class="error">{field.error}</div>}
</>
)}
</Field>
<button type="submit">Post</button>
</Form>
);
});