diff --git a/examples/errorsAndValidation.tsx b/examples/errorsAndValidation.tsx
index 476ebf6..28b76c4 100644
--- a/examples/errorsAndValidation.tsx
+++ b/examples/errorsAndValidation.tsx
@@ -7,10 +7,24 @@ const Index: React.FC = () => {
const { auto, form, errors } = useForm({
username: '',
+ email: '',
password: ''
}, {
username: value => value.length > 3,
- password: /[\d]{1,}/
+ email: {
+ validator: /@/,
+ message: 'Must contain an @',
+ },
+ password: [
+ {
+ validator: /[A-Z]/,
+ message: 'Must contain an uppercase letter'
+ },
+ {
+ validator: /[\d]/,
+ message: 'Must contain a digit'
+ },
+ ]
})
return (
@@ -21,8 +35,11 @@ const Index: React.FC = () => {
{errors.username && 'Must be longer than 3'}
+
+ {errors.email}
+
- {errors.password && 'Must contain a number'}
+ {errors.password}
)
diff --git a/lib/index.ts b/lib/index.ts
index 6f2a977..60de332 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React, { useState, useEffect } from 'react'
@@ -20,13 +20,26 @@ export type useFormValidatorObject = {
export type useFormValidator = useFormValidatorMethod | useFormValidatorObject
+export type useFormValidatorParameter = useFormValidator | useFormValidator[]
+
export const HTMLInputExtractor: useFormExtractor = (e: React.FormEvent) => e.currentTarget.value
export const HTMLCheckboxExtractor: useFormExtractor = (e: React.FormEvent) => e.currentTarget.checked
-export const useForm = (init: T, validators: Partial = {}, options: useFormOptions = {}) => {
+function isFormValidatorObject(validator: useFormValidatorMethod | useFormValidatorObject): validator is useFormValidatorObject {
+ return validator.constructor.name === 'Object'
+}
+
+const defaultErrorMessage = (key: any) => `Error in ${key}`
+
+export const useForm = (init: T, validators: Partial = {}, options: useFormOptions = {}) => {
const [form, setForm] = useState(init)
const [errors, setErrors] = useState>({})
+ const [isValid, setIsValid] = useState(true);
+
+ useEffect(() => {
+ setIsValid(!Object.values(errors).reduce((acc, cur) => acc || cur !== undefined, false))
+ }, [errors])
const _set = (key: keyof T, value: any) => {
setForm({
@@ -35,34 +48,48 @@ export const useForm = => {
- if (validator.constructor.name === 'Function' || validator.constructor.name === 'AsyncFunction')
+ const _validateAll = async (value: any, object: useFormValidator): Promise => {
+ const validator = isFormValidatorObject(object) ? object.validator : object
+
+ if (validator.constructor.name === 'Function')
return (validator as useFormValidatorFunction)(value)
+ else if (validator.constructor.name === 'AsyncFunction')
+ return await (validator as useFormValidatorFunction)(value)
else if (validator.constructor.name === 'RegExp')
return (validator as RegExp).test(value)
else return false
}
- const _getValidatorMessage = (key: keyof T): string => {
- // @ts-ignore
- if (validators[key] && validators[key].message) return validators[key].message
- else return `Error in: ${key}`
- }
-
const _validate = (key: keyof T, value: any) => {
- const validator: useFormValidator | undefined = validators[key]
+ const validator: useFormValidatorParameter | undefined = validators[key]
if (!validator) return
- // @ts-ignore
- _validateAll(value, validator.constructor.name === 'Object' ? (validator as useFormValidatorObject).validator : validator)
- .then((valid: boolean) => {
- setErrors({
- ...errors,
- [key]: valid
- ? undefined
- : _getValidatorMessage(key),
+ if (Array.isArray(validator)) {
+ Promise.all(validator.map(v => _validateAll(value, v)))
+ .then(result => {
+ const index = result.indexOf(false)
+ setErrors({
+ ...errors,
+ [key]: index === -1
+ ? undefined
+ : isFormValidatorObject(validator[index]) && (validator[index] as useFormValidatorObject).message
+ ? (validator[index] as useFormValidatorObject).message
+ : defaultErrorMessage(key)
+ })
})
- })
+ } else {
+ _validateAll(value, validator)
+ .then(valid => {
+ setErrors({
+ ...errors,
+ [key]: valid
+ ? undefined
+ : isFormValidatorObject(validator) && validator.message
+ ? validator.message
+ : defaultErrorMessage(key)
+ })
+ })
+ }
}
const update = (key: keyof T, extractor = options.extractor) => (value: any) => {
@@ -76,5 +103,5 @@ export const useForm = = ({ error }) => !error
const Index: React.FC = () => {
- const { auto, form, errors } = useForm({
+ const { auto, form, errors, isValid } = useForm({
username: '',
password: '',
type: 'formhero',
awesome: true,
}, {
- username: /^test/,
+ username: [
+ /^test/,
+ {
+ validator: async () => { return true },
+ message: 'Digits please',
+ }
+ ],
password: {
validator: /^.{3,}$/,
message: 'To short',
@@ -26,7 +32,7 @@ const Index: React.FC = () => {
const _submit = (e: React.FormEvent) => {
e.preventDefault()
- console.log(form, errors)
+ console.log(form, errors, isValid)
}
return (