use-form-input
Advanced tools
Comparing version 1.1.1 to 1.2.0
import * as React from 'react'; | ||
declare type ErrorType<T> = { | ||
[key in keyof T]: { | ||
error: boolean; | ||
messages: Array<string>; | ||
}; | ||
}; | ||
declare type ValueType = object | [] | string | boolean | number; | ||
declare type ValidatorConfigType = { | ||
condition: boolean; | ||
message?: string; | ||
onMatch?: (messages?: string) => void; | ||
}; | ||
declare type ValidatorType<T> = (errors: any) => (name: keyof T, config: ValidatorConfigType) => void; | ||
export declare function useFormInput<T>(fields: T): [ | ||
import { ErrorType, ValidatorType, ValueType } from './types'; | ||
export declare function useFormInput<T>(fields: T, handleSubmit?: (data: T) => void, validation?: (data: T) => any): [ | ||
T, | ||
{ | ||
onChange: (name: keyof T, value?: ValueType | ((previousValue: ValueType) => any)) => (event?: React.ChangeEvent<any>) => void; | ||
setValue: (name?: keyof T, value?: ValueType | ((previousValue: ValueType) => any)) => void; | ||
onChange: (event?: React.ChangeEvent<any>) => void; | ||
onSubmit: (e: React.FormEvent) => void; | ||
validator: ValidatorType<T>; | ||
@@ -23,4 +13,5 @@ isValid: (errors: ErrorType<T> | {}) => boolean; | ||
setErrors: React.Dispatch<React.SetStateAction<{}>>; | ||
clear: () => void; | ||
modified: T; | ||
} | ||
]; | ||
export {}; |
@@ -25,38 +25,66 @@ Object.defineProperty(exports, '__esModule', { value: true }); | ||
function useFormInput(fields) { | ||
// compares two object and returns new object comparing two | ||
function compareObjectKeys(object1, object2) { | ||
const result = {}; | ||
Object.keys(object1).forEach((k) => { | ||
if (String(object1[k]) !== String(object2[k])) { | ||
result[k] = true; | ||
} | ||
}); | ||
return result; | ||
} | ||
function useFormInput(fields, handleSubmit, validation) { | ||
const [data, setData] = React__namespace.useState(Object.assign({}, fields)); | ||
const [errors, setErrors] = React__namespace.useState({}); | ||
const onChange = (name, value) => { | ||
return function (event) { | ||
event === null || event === void 0 ? void 0 : event.persist(); | ||
setData((prev) => { | ||
var _a; | ||
if (value === undefined || value === null) { | ||
return Object.assign(Object.assign({}, prev), { [name]: (_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.value }); | ||
} | ||
else { | ||
if (typeof value === 'function') { | ||
const functionReturnValue = value(prev[name]); | ||
return Object.assign(Object.assign({}, prev), { [name]: functionReturnValue }); | ||
} | ||
else { | ||
return Object.assign(Object.assign({}, prev), { [name]: value }); | ||
} | ||
} | ||
}); | ||
}; | ||
const [modified, setModified] = React__namespace.useState({}); | ||
// called every time data is changed | ||
React__namespace.useEffect(() => { | ||
if (validation) { | ||
const catchedErrors = validation(data); | ||
setErrors(catchedErrors); | ||
} | ||
}, [data]); | ||
// checks whether the data is modified or not | ||
React__namespace.useEffect(() => { | ||
const compared = compareObjectKeys(fields, data); | ||
const newlyModified = Object.assign(Object.assign({}, modified), compared); | ||
setModified(newlyModified); | ||
}, [data]); | ||
// setValue to set the individual items | ||
const setValue = (name, value) => { | ||
setData((prev) => { | ||
if (typeof value === 'function') { | ||
const functionReturnValue = value(prev[name]); | ||
return Object.assign(Object.assign({}, prev), { [name]: functionReturnValue }); | ||
} | ||
else { | ||
return Object.assign(Object.assign({}, prev), { [name]: value }); | ||
} | ||
}); | ||
}; | ||
// onChange for `named` form fields | ||
const onChange = function (event) { | ||
// for previous version of react ( pooling ) | ||
event === null || event === void 0 ? void 0 : event.persist(); | ||
const fieldName = event === null || event === void 0 ? void 0 : event.target.name; | ||
if (!fieldName) { | ||
throw new Error(`'name' attribute is missing in props`); | ||
} | ||
setData((prev) => { | ||
var _a; | ||
return Object.assign(Object.assign({}, prev), { [fieldName]: (_a = event === null || event === void 0 ? void 0 : event.target) === null || _a === void 0 ? void 0 : _a.value }); | ||
}); | ||
}; | ||
// validator | ||
const validator = (errors) => { | ||
return function (name, config) { | ||
var _a, _b; | ||
var _a; | ||
const { condition, message, onMatch } = config; | ||
if (condition) { | ||
errors[name] = { | ||
error: true, | ||
messages: (_b = (_a = errors[name]) === null || _a === void 0 ? void 0 : _a.messages) !== null && _b !== void 0 ? _b : [], | ||
}; | ||
errors[name] = (_a = errors[name]) !== null && _a !== void 0 ? _a : []; | ||
const hasErrorMessage = message !== null && message !== undefined; | ||
if (Object.prototype.hasOwnProperty.call(errors, name)) { | ||
if (hasErrorMessage) { | ||
errors[name].messages = [...errors[name].messages, message]; | ||
errors[name] = [...errors[name], message]; | ||
} | ||
@@ -66,3 +94,3 @@ } | ||
if (hasErrorMessage) { | ||
errors[name].messages = [message]; | ||
errors[name] = [message]; | ||
} | ||
@@ -79,8 +107,55 @@ } | ||
}; | ||
// checks whether the errors is empty or not | ||
const isValid = (errors) => { | ||
return Object.keys(errors).length === 0; | ||
}; | ||
// clears the form | ||
const clear = () => { | ||
const formData = Object.keys(data).map((val) => { | ||
const field = data[val]; | ||
return { | ||
key: val, | ||
value: field, | ||
valueType: typeof field, | ||
}; | ||
}); | ||
const emptyData = formData.reduce((acc, curr) => { | ||
let resetValue; | ||
if (curr.valueType === 'boolean') { | ||
resetValue = false; | ||
} | ||
else { | ||
resetValue = ''; | ||
} | ||
return Object.assign(Object.assign({}, acc), { [curr.key]: resetValue }); | ||
}, Object.assign({}, data)); | ||
setData(emptyData); | ||
}; | ||
// handle the submit | ||
const onSubmit = (e) => { | ||
e.preventDefault(); | ||
const modifiedData = Object.keys(fields).reduce((acc, curr) => { | ||
return Object.assign(Object.assign({}, acc), { [curr]: true }); | ||
}, {}); | ||
setModified(modifiedData); | ||
if (!isValid(errors)) { | ||
return; | ||
} | ||
if (handleSubmit) { | ||
handleSubmit(data); | ||
} | ||
}; | ||
return [ | ||
data, | ||
React__namespace.useMemo(() => ({ onChange, validator, isValid, errors, setErrors }), [errors]), | ||
React__namespace.useMemo(() => ({ | ||
setValue, | ||
onChange, | ||
validator, | ||
isValid, | ||
errors, | ||
setErrors, | ||
clear, | ||
modified, | ||
onSubmit, | ||
}), [errors, modified]), | ||
]; | ||
@@ -87,0 +162,0 @@ } |
{ | ||
"name": "use-form-input", | ||
"version": "1.1.1", | ||
"version": "1.2.0", | ||
"description": "Simple hook to provide form validation in react", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
248
README.md
@@ -8,8 +8,8 @@ # USE-FORM-INPUT | ||
- Small size and no dependencies | ||
- Easy to use APIs | ||
- Fully customizable form handling and validations | ||
- Easy to use | ||
### Install | ||
### Installation | ||
Install with npm: | ||
Install: | ||
@@ -22,32 +22,154 @@ ```sh | ||
#### 1. Basic form handling | ||
Form handling can be done with `useFormInput`. | ||
Example: | ||
```jsx | ||
// Basic form handling | ||
import { useFormInput } from 'use-form-input'; | ||
export default function App() { | ||
const [data, { onChange, validator, isValid, errors, setErrors }] = | ||
export default function BasicFormHandling() { | ||
const [data, { onChange, onSubmit }] = useFormInput( | ||
{ | ||
firstName: '', | ||
lastName: '', | ||
}, | ||
(data) => { | ||
console.log('FINAL DATA', data); | ||
} | ||
); | ||
return ( | ||
<> | ||
<form onSubmit={onSubmit} style={{ marginLeft: 10 }}> | ||
<input | ||
type="text" | ||
name="firstName" | ||
value={data.firstName} | ||
onChange={onChange} | ||
/> | ||
<br /> | ||
<input | ||
type="text" | ||
name="lastName" | ||
value={data.lastName} | ||
onChange={onChange} | ||
/> | ||
<br /> | ||
<input value="Submit" type="submit" /> | ||
</form> | ||
</> | ||
); | ||
} | ||
``` | ||
Note: The form element must have `name` prop available to use `onChange`. | ||
#### 2. Form Validation | ||
Form validation can be done by passing third parameter ( function ) which should return an error object. | ||
The function is called with the data. | ||
Example: | ||
```jsx | ||
import { useFormInput } from 'use-form-input'; | ||
export default function FormValidation() { | ||
const [data, { onChange, onSubmit, errors, modified }] = useFormInput( | ||
{ | ||
firstName: '', | ||
lastName: '', | ||
}, | ||
(data) => { | ||
console.log('FINAL DATA', data); | ||
}, | ||
(data) => { | ||
const errors = {}; | ||
if (data.firstName.length === 0) { | ||
errors.firstName = 'Empty first name'; | ||
} | ||
if (data.lastName.length === 0) { | ||
errors.lastName = 'Empty last name'; | ||
} | ||
return errors; | ||
} | ||
); | ||
return ( | ||
<> | ||
<form onSubmit={onSubmit} style={{ marginLeft: 10 }}> | ||
<input | ||
type="text" | ||
name="firstName" | ||
value={data.firstName} | ||
onChange={onChange} | ||
/> | ||
{modified.firstName && errors.firstName && ( | ||
<span style={{ color: 'red' }}>{errors.firstName}</span> | ||
)} | ||
<br /> | ||
<input | ||
type="text" | ||
name="lastName" | ||
value={data.lastName} | ||
onChange={onChange} | ||
/> | ||
{modified.lastName && errors.lastName && ( | ||
<span style={{ color: 'red' }}>{errors.lastName}</span> | ||
)} | ||
<br /> | ||
<input value="Submit" type="submit" /> | ||
</form> | ||
</> | ||
); | ||
} | ||
``` | ||
Note: `modified` object is used so that, the error is not shown by default. The form should either be submitted or certain fields must change before it should show error. `modified` object has the property same as fields passed to `useFormInput` hook. | ||
#### 3. Manual Validation | ||
Form can be manually validated by using `validator`, `setErrors` and `isValid` methods. | ||
Example: | ||
```jsx | ||
import { useFormInput } from 'use-form-input'; | ||
export default function ManualValidation() { | ||
const [data, { onChange, errors, setErrors, isValid, validator }] = | ||
useFormInput({ | ||
name: 'John Doe', | ||
firstName: '', | ||
lastName: '', | ||
}); | ||
const onSubmit = (e: React.FormEvent) => { | ||
const onSubmit = (e) => { | ||
e.preventDefault(); | ||
const cachedErrors = {}; | ||
const validate = validator(cachedErrors); | ||
const catchedErrors = {}; | ||
const validate = validator(catchedErrors); | ||
const { name } = data; | ||
validate('firstName', { | ||
condition: data.firstName.length === 0, | ||
message: 'Empty first name', | ||
}); | ||
validate('name', { | ||
condition: name.length === 0, | ||
message: 'Empty name', | ||
onMatch: function (message) { | ||
if (message) { | ||
console.error(message); | ||
} | ||
}, | ||
validate('lastName', { | ||
condition: data.lastName.length === 0, | ||
message: 'Emptry last name', | ||
}); | ||
setErrors(cachedErrors); | ||
setErrors(catchedErrors); | ||
if (!isValid(cachedErrors)) { | ||
if (!isValid(catchedErrors)) { | ||
return; | ||
@@ -64,11 +186,22 @@ } | ||
type="text" | ||
placeholder="name" | ||
value={data.name} | ||
onChange={onChange('name')} | ||
name="firstName" | ||
value={data.firstName} | ||
onChange={onChange} | ||
/> | ||
<p style={{ color: 'red' }}> | ||
{errors.name && | ||
errors.name.messages.length > 0 && | ||
errors.name.messages[0]} | ||
</p> | ||
{errors.firstName && ( | ||
<span style={{ color: 'red' }}>{errors.firstName}</span> | ||
)} | ||
<br /> | ||
<input | ||
type="text" | ||
name="lastName" | ||
value={data.lastName} | ||
onChange={onChange} | ||
/> | ||
{errors.lastName && ( | ||
<span style={{ color: 'red' }}>{errors.lastName}</span> | ||
)} | ||
<br /> | ||
<input value="Submit" type="submit" /> | ||
@@ -81,4 +214,63 @@ </form> | ||
#### 4. Manually Setting Values | ||
We need a method to manually set the values of certain fields. We can do it by using `setValue` method. | ||
Example: | ||
```jsx | ||
const [data, { setValue }] = useFormInput({ firstName: '' }); | ||
... | ||
<input | ||
type="text" | ||
name="firstName" | ||
value={data.firstName} | ||
onChange={e => setValue('firstName', e.target.value)} | ||
/> | ||
``` | ||
`setValue` accepts two parameters: | ||
1. Field Name | ||
2. Value | ||
#### 5. Modifiying previous values | ||
We can modify the previous values using `setValue` method. For example, we can use it in checkbox. | ||
Example: | ||
```jsx | ||
const [data, { setValue }] = useFormInput({ married: false }); | ||
... | ||
<input | ||
type="text" | ||
name="married" | ||
checked={data.married} | ||
onChange={e => setValue('married', (previousValue) => !previousValue)} | ||
/> | ||
``` | ||
It works like a `setState` function, getting previous value and returning modified one. | ||
#### 6. Clearing form | ||
We can clear the from by using `clear` method which sets all the modified fields to its initial one. | ||
Example: | ||
```jsx | ||
const [data, { clear }] = useFormInput({ firstName: '', lastName: '' }); | ||
... | ||
<button onClick={() => clear()}>Clear</button> | ||
``` | ||
## License | ||
MIT |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24099
8
186
273