diff --git a/packages/common/types/control.types.ts b/packages/common/types/control.types.ts
index 2c6adb7..1e62922 100644
--- a/packages/common/types/control.types.ts
+++ b/packages/common/types/control.types.ts
@@ -1,4 +1,4 @@
-import type { ValidatorRules } from "./validator.types";
+import type { ValidationHooks, ValidatorRules } from "./validator.types";
/**
* `ControlType` determines the type of form control
@@ -37,6 +37,7 @@ export interface ControlBase {
label?: string;
placeholder?: string;
validators?: ValidatorRules;
+ triggerValidationOn?: ValidationHooks;
}
export interface Checkbox extends ControlBase {
diff --git a/packages/common/types/validator.types.ts b/packages/common/types/validator.types.ts
index 0685a09..e199884 100644
--- a/packages/common/types/validator.types.ts
+++ b/packages/common/types/validator.types.ts
@@ -1,5 +1,7 @@
export type HookType = "onSubmit" | "onControlBlur" | "all";
+export type ValidationHooks = "" | "blur" | "keypress" | "click"; // More to be added
+
export type CategoryType = "error" | "warn" | "info";
export type ValidatorRules =
diff --git a/packages/form/components/controls/Dropdown.astro b/packages/form/components/controls/Dropdown.astro
index bd0a350..cf61438 100644
--- a/packages/form/components/controls/Dropdown.astro
+++ b/packages/form/components/controls/Dropdown.astro
@@ -6,7 +6,7 @@ import type { Dropdown, ControlOption } from '@astro-reactive/common';
export interface Props {
control: Dropdown;
- readOnly?: boolean;
+ readOnly?: boolean;
}
const { control, readOnly } = Astro.props;
@@ -26,22 +26,20 @@ const options = control.options.map((option: string | ControlOption) => {
name={control.name}
id={control.id}
disabled={readOnly || null}
+ data-validation-on={control.triggerValidationOn ? control.triggerValidationOn : null}
>
-{
- control?.placeholder && (
-
- )
-}
-{
- options.map((option: ControlOption) => (
-
- ))
-}
+ {
+ control?.placeholder && (
+
+ )
+ }
+ {
+ options.map((option: ControlOption) => (
+
+ ))
+ }
diff --git a/packages/form/components/controls/Input.astro b/packages/form/components/controls/Input.astro
index 63b76dd..f8aa66b 100644
--- a/packages/form/components/controls/Input.astro
+++ b/packages/form/components/controls/Input.astro
@@ -46,6 +46,7 @@ const validatorAttributes: Record = validators.reduce((prev, val
data-validator-error={hasError ? hasError.toString() : null}
data-validator-warn={hasWarn ? hasWarn.toString() : null}
data-validator-info={hasInfo ? hasInfo.toString() : null}
+ data-validation-on={control.triggerValidationOn ? control.triggerValidationOn : null}
readonly={readOnly || null}
disabled={(readOnly || null) && control.type === 'checkbox'}
{...validatorAttributes}
diff --git a/packages/form/components/controls/RadioGroup.astro b/packages/form/components/controls/RadioGroup.astro
index ea90f94..25b2468 100644
--- a/packages/form/components/controls/RadioGroup.astro
+++ b/packages/form/components/controls/RadioGroup.astro
@@ -33,6 +33,7 @@ const options = control.options.map((option: string | ControlOption) => {
checked={option.value === control.value}
readonly={readOnly || null}
disabled={readOnly || null}
+ data-validation-on={control.triggerValidationOn ? control.triggerValidationOn : null}
/>
diff --git a/packages/form/components/controls/TextArea.astro b/packages/form/components/controls/TextArea.astro
index bc0741c..15ff124 100644
--- a/packages/form/components/controls/TextArea.astro
+++ b/packages/form/components/controls/TextArea.astro
@@ -38,6 +38,7 @@ const validatorAttributes: Record = validators.reduce((prev, val
cols={control?.cols ?? 21}
data-label={control?.label}
readonly={readOnly || null}
+ data-validation-on={control.triggerValidationOn ? control.triggerValidationOn : null}
{...validatorAttributes}
>
{control.value}
diff --git a/packages/form/core/form-control.ts b/packages/form/core/form-control.ts
index 48b5667..12c775c 100644
--- a/packages/form/core/form-control.ts
+++ b/packages/form/core/form-control.ts
@@ -10,6 +10,7 @@ import type {
TextArea,
ControlBase,
ValidatorRules,
+ ValidationHooks,
} from '@astro-reactive/common';
import ShortUniqueId from 'short-unique-id';
@@ -25,6 +26,7 @@ export class FormControl {
private _isPristine = true;
private _placeholder: string | null = null;
private _validators: ValidatorRules = [];
+ private _triggerValidationOn: ValidationHooks;
private _errors: ValidationError[] = [];
private _options: string[] | ControlOption[] = [];
private _rows: number | null = null;
@@ -47,6 +49,7 @@ export class FormControl {
label = '',
placeholder = null,
validators = [],
+ triggerValidationOn = 'blur',
} = config;
const uid = new ShortUniqueId({ length: 9 });
@@ -57,6 +60,7 @@ export class FormControl {
this._label = label;
this._placeholder = placeholder;
this._validators = validators;
+ this._triggerValidationOn = triggerValidationOn;
if (type === 'radio' || type === 'dropdown') {
const { options = [] } = config as Radio | Dropdown;
@@ -111,6 +115,10 @@ export class FormControl {
return this._validators;
}
+ get triggerValidationOn() {
+ return this._triggerValidationOn;
+ }
+
get errors() {
return this._errors;
}
diff --git a/packages/validator/Validator.astro b/packages/validator/Validator.astro
index 25b0701..edb74b5 100644
--- a/packages/validator/Validator.astro
+++ b/packages/validator/Validator.astro
@@ -28,10 +28,10 @@ const { hook = 'all', displayErrorMessages = false } = Astro.props;
import { clearErrors, validate } from './core';
// const hook: HookType = (document.getElementById('hook') as HTMLInputElement).value as HookType;
- const inputs = [...document.querySelectorAll('form input')] as HTMLInputElement[];
+ const inputs = [...document.querySelectorAll('body *[data-validation-on]')] as HTMLInputElement[];
inputs?.forEach((input) => {
- input.addEventListener('blur', (e: Event) => {
+ input.addEventListener(input.dataset?.validationOn ?? 'blur', (e: Event) => {
// NOTE: event target attribute names are converted to lowercase
const element = e.target as HTMLInputElement;
const attributeNames = element?.getAttributeNames() || [];