Fixxed bugs Form Validation
This commit is contained in:
+40
-11
@@ -83,7 +83,8 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<!-- Client validation & submit hook (no zod import here) -->
|
<!-- Client validation & submit hook (no zod import here) -->
|
||||||
<script type="module" define:vars={{ formId, showSuccesInput }}>
|
<script type="module" is:inline define:vars={{ formId, showSuccesInput }}>
|
||||||
|
const start = () => {
|
||||||
const INVALID_KLS = ["!border-danger", "focus-visible:ring-danger/40"];
|
const INVALID_KLS = ["!border-danger", "focus-visible:ring-danger/40"];
|
||||||
const VALID_KLS = ["!border-success", "focus-visible:ring-success/40"];
|
const VALID_KLS = ["!border-success", "focus-visible:ring-success/40"];
|
||||||
|
|
||||||
@@ -115,7 +116,8 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
(el) => el instanceof HTMLInputElement && el.type === "radio",
|
(el) => el instanceof HTMLInputElement && el.type === "radio",
|
||||||
);
|
);
|
||||||
const checks = all.filter(
|
const checks = all.filter(
|
||||||
(el) => el instanceof HTMLInputElement && el.type === "checkbox",
|
(el) =>
|
||||||
|
el instanceof HTMLInputElement && el.type === "checkbox",
|
||||||
);
|
);
|
||||||
|
|
||||||
const err = root.querySelector('[id$="-err"]');
|
const err = root.querySelector('[id$="-err"]');
|
||||||
@@ -157,7 +159,9 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
|
|
||||||
function clearState(root) {
|
function clearState(root) {
|
||||||
const { ctrls, err } = fieldControls(root);
|
const { ctrls, err } = fieldControls(root);
|
||||||
ctrls.forEach((c) => c.classList.remove(...INVALID_KLS, ...VALID_KLS));
|
ctrls.forEach((c) =>
|
||||||
|
c.classList.remove(...INVALID_KLS, ...VALID_KLS),
|
||||||
|
);
|
||||||
ctrls[0]?.removeAttribute("aria-invalid");
|
ctrls[0]?.removeAttribute("aria-invalid");
|
||||||
if (err) {
|
if (err) {
|
||||||
err.textContent = "";
|
err.textContent = "";
|
||||||
@@ -183,11 +187,13 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
formEl.querySelectorAll(`[name="${CSS.escape(name)}"]`),
|
formEl.querySelectorAll(`[name="${CSS.escape(name)}"]`),
|
||||||
);
|
);
|
||||||
const radios = els.filter(
|
const radios = els.filter(
|
||||||
(el) => el instanceof HTMLInputElement && el.type === "radio",
|
(el) =>
|
||||||
|
el instanceof HTMLInputElement && el.type === "radio",
|
||||||
);
|
);
|
||||||
const checks = els.filter(
|
const checks = els.filter(
|
||||||
(el) =>
|
(el) =>
|
||||||
el instanceof HTMLInputElement && el.type === "checkbox",
|
el instanceof HTMLInputElement &&
|
||||||
|
el.type === "checkbox",
|
||||||
);
|
);
|
||||||
|
|
||||||
if (radios.length) {
|
if (radios.length) {
|
||||||
@@ -210,8 +216,13 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
const el = els[0];
|
const el = els[0];
|
||||||
|
|
||||||
if (el instanceof HTMLSelectElement && el.multiple) {
|
if (el instanceof HTMLSelectElement && el.multiple) {
|
||||||
data[name] = Array.from(el.selectedOptions).map((o) => o.value);
|
data[name] = Array.from(el.selectedOptions).map(
|
||||||
} else if (el instanceof HTMLInputElement && el.type === "file") {
|
(o) => o.value,
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
el instanceof HTMLInputElement &&
|
||||||
|
el.type === "file"
|
||||||
|
) {
|
||||||
data[name] = el.multiple
|
data[name] = el.multiple
|
||||||
? Array.from(el.files || [])
|
? Array.from(el.files || [])
|
||||||
: (el.files?.[0] ?? null);
|
: (el.files?.[0] ?? null);
|
||||||
@@ -249,7 +260,9 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
const schema = getSchema();
|
const schema = getSchema();
|
||||||
if (!schema || !schema.shape || !schema.shape[name]) return;
|
if (!schema || !schema.shape || !schema.shape[name]) return;
|
||||||
|
|
||||||
const root = form.querySelector(`[data-field="${CSS.escape(name)}"]`);
|
const root = form.querySelector(
|
||||||
|
`[data-field="${CSS.escape(name)}"]`,
|
||||||
|
);
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
|
|
||||||
const { ctrls, isRadioGroup, isMultiCheckbox, checkboxes } =
|
const { ctrls, isRadioGroup, isMultiCheckbox, checkboxes } =
|
||||||
@@ -275,7 +288,10 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
} else {
|
} else {
|
||||||
// single control
|
// single control
|
||||||
const ctrl = ctrls[0];
|
const ctrl = ctrls[0];
|
||||||
if (ctrl instanceof HTMLInputElement && ctrl.type === "checkbox") {
|
if (
|
||||||
|
ctrl instanceof HTMLInputElement &&
|
||||||
|
ctrl.type === "checkbox"
|
||||||
|
) {
|
||||||
value = ctrl.checked;
|
value = ctrl.checked;
|
||||||
} else if (
|
} else if (
|
||||||
ctrl instanceof HTMLInputElement &&
|
ctrl instanceof HTMLInputElement &&
|
||||||
@@ -285,7 +301,9 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
? Array.from(ctrl.files || [])
|
? Array.from(ctrl.files || [])
|
||||||
: (ctrl.files?.[0] ?? null);
|
: (ctrl.files?.[0] ?? null);
|
||||||
} else if (ctrl instanceof HTMLSelectElement && ctrl.multiple) {
|
} else if (ctrl instanceof HTMLSelectElement && ctrl.multiple) {
|
||||||
value = Array.from(ctrl.selectedOptions).map((o) => o.value);
|
value = Array.from(ctrl.selectedOptions).map(
|
||||||
|
(o) => o.value,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
value = ctrl.value;
|
value = ctrl.value;
|
||||||
}
|
}
|
||||||
@@ -294,7 +312,9 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
const res = schema.shape[name].safeParse(value);
|
const res = schema.shape[name].safeParse(value);
|
||||||
setError(
|
setError(
|
||||||
root,
|
root,
|
||||||
res.success ? "" : res.error.issues[0]?.message || "Invalid value",
|
res.success
|
||||||
|
? ""
|
||||||
|
: res.error.issues[0]?.message || "Invalid value",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,4 +407,13 @@ const formId = `f-${Math.random().toString(36).slice(2)}`;
|
|||||||
t.value = t.getAttribute("data-initial") || "";
|
t.value = t.getAttribute("data-initial") || "";
|
||||||
t.removeAttribute("data-initial");
|
t.removeAttribute("data-initial");
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (document.readyState === "loading") {
|
||||||
|
document.addEventListener("DOMContentLoaded", start, { once: true });
|
||||||
|
} else {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
// For Astro client routing / view transitions
|
||||||
|
document.addEventListener("astro:page-load", start);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user