|
1 |
| -# React AJV Schema |
| 1 | +# useAjvForm |
2 | 2 |
|
3 |
| - |
| 3 | +<p align="center" style="width:300px; margin: auto;"> |
| 4 | + <img src="./assets/ajv-react.png"> |
| 5 | +</p> |
4 | 6 |
|
5 |
| -[use-ajv-form](https://github.com/agjs/use-ajv-form) is a custom React Hook that enables you to generate your form logic and validation based on [Ajv JSON Schema Validator](https://ajv.js.org/). |
| 7 | +[use-ajv-form](https://github.com/agjs/use-ajv-form) is a custom React Hook enabling powerful and efficient form logic and validation using [Ajv JSON Schema Validator](https://ajv.js.org/). It offers an elegant solution to integrate state and validation into any form, independent of the form's design and presentation. |
6 | 8 |
|
7 |
| -It integrates seamlessly with any form and is completely agnostic from your form markup. It simply provides the state and validation. You choose how you want to present the errors and organise your forms. In simple words, it's completely decoupled from how your forms work, look and feel. |
| 9 | +This library is a part of the toolkit used extensively on [Programmer Network](https://programmer.network/). It is an open-source project, fostered by our vibrant community on the [Programmer Network Twitch Channel](https://twitch.tv/programmer_network). |
8 | 10 |
|
9 |
| -## Why |
| 11 | +## Why Use React AJV Schema? |
10 | 12 |
|
11 |
| -Validating forms manually is a painful process. Ajv solves that by not only providing validation based on valid [JSON Schema Specification](https://json-schema.org/specification.html), but also, provides [plugins](https://ajv.js.org/packages/) that allows further extension and creation of custom validators. That means that you can extend your schema with infinite amount of validators, and keep your forms still purely depend on the schema, without introducing manual if statements all over the place. |
12 |
| - |
13 |
| -This library is used by all forms on [Programmer Network](https://programmer.network/) and is Open Sourced due to our amazing community on an official [Programmer Network Twitch Channel](https://twitch.tv/programmer_network). |
14 |
| - |
15 |
| ---- |
| 13 | +- **Streamlined Form Validation**: Uses Ajv to automate form validation against the [JSON Schema Specification](https://json-schema.org/specification.html), significantly reducing the need for manual validation. |
| 14 | +- **Plugin Extensibility**: Supports Ajv [plugins](https://ajv.js.org/packages/) for custom validators, enhancing schema flexibility. |
| 15 | +- **Design Agnostic**: Offers full freedom in how you structure, style, and handle your forms. |
16 | 16 |
|
17 | 17 | ## Features
|
18 | 18 |
|
19 |
| -- Form JSON Schema Validation ✔️ |
20 |
| -- Dirty state checking ✔️ |
21 |
| -- Consume remote errors as part of the schema, e.g. `username already taken`. In simple words, errors coming from your API ✔️ |
22 |
| -- Maps 1:1 with nested objects. In simple words, a form can generate the exact object shape that you want, no need for manual mapping before e.g. API submission ✔️ |
23 |
| - |
24 |
| ---- |
25 |
| - |
26 |
| -## Install |
27 |
| - |
28 |
| -`yarn add @programmer_network/use-ajv-form` |
29 |
| - |
30 |
| -or |
31 |
| - |
32 |
| -`npm install @programmer_network/use-ajv-form` |
33 |
| - |
34 |
| ---- |
35 |
| - |
36 |
| -## Usage |
37 |
| - |
38 |
| -[Codesandbox Live Demo](https://google.com) |
| 19 | +- **JSON Schema Validation**: Validates form data against a specified JSON schema. |
| 20 | +- **Dirty State Tracking**: Identifies changes in form fields. |
| 21 | +- **Remote Error Handling**: Manages errors from external sources (like APIs) as part of schema validation. |
39 | 22 |
|
40 |
| -Let's start with a simple example. |
| 23 | +## Installation |
41 | 24 |
|
42 |
| -Let's create our form object. This object contains methods and state that our form will depend on. |
43 |
| - |
44 |
| -```javascript |
45 |
| -import { useAjvForm } from '@programmer_network/useAjvForm'; |
46 |
| - |
47 |
| -const initialState = { |
48 |
| - title: '', |
49 |
| - description: '', |
50 |
| -}; |
51 |
| - |
52 |
| -const schema = { |
53 |
| - type: 'object', |
54 |
| - required: ['title'], |
55 |
| - properties: { |
56 |
| - title: { |
57 |
| - type: 'string', |
58 |
| - }, |
59 |
| - description: { |
60 |
| - type: 'string', |
61 |
| - minLength: 20, |
62 |
| - errorMessages: { |
63 |
| - minLength: 'Description is too short. At least 20 characters expected.', |
64 |
| - }, |
65 |
| - }, |
66 |
| - }, |
67 |
| -}; |
68 |
| - |
69 |
| -const form = useAjvForm(initialState, schema, remoteErrors); |
70 |
| -``` |
71 |
| - |
72 |
| -Then we create a onSubmit form handler that will call our validators. |
73 |
| - |
74 |
| -```js |
75 |
| -const handleSubmit = (event) => { |
76 |
| - event.preventDefault(); |
77 |
| - |
78 |
| - if (!form.validate()) { |
79 |
| - // form is invalid, exit early |
80 |
| - // when this happens, our hook will update the fields that failed validation |
81 |
| - return; |
82 |
| - } |
83 |
| - |
84 |
| - // validation successful, call some API |
85 |
| - axios.post('someUrl', form.data); |
86 |
| -}; |
| 25 | +```bash |
| 26 | +pnpm add @programmer_network/use-ajv-form |
| 27 | +# or |
| 28 | +bun install @programmer_network/use-ajv-form |
| 29 | +# or |
| 30 | +yarn add @programmer_network/use-ajv-form |
| 31 | +# or |
| 32 | +npm install @programmer_network/use-ajv-form |
87 | 33 | ```
|
88 |
| - |
89 |
| -Generally, your own Input component takes a value and an error. If you are using component composition, this might look a bit different, but you get the point. |
90 |
| - |
91 |
| -```jsx |
92 |
| -// your custom input component |
93 |
| -const CustomInput = ({ value, error, name }) => { |
94 |
| - <input type="text" name={name} value={value} />; |
95 |
| - { |
96 |
| - error && <span>{error}</span>; |
97 |
| - } |
98 |
| -}; |
99 |
| -``` |
100 |
| - |
101 |
| -As you may notice, for every given property in your schema, our hook will create a value and error properties. Error property is initially set to null, and the value to whatever values are set in your initial state. |
102 |
| - |
103 |
| -```jsx |
104 |
| -<form onSubmit={handleSubmit}> |
105 |
| - <CustomInput name="title" value={form.state.title.value} /> |
106 |
| - <CustomInput name="description" value={form.state.description.value} /> |
107 |
| - <button type="submit">Submit</button> |
108 |
| -</form> |
109 |
| -``` |
110 |
| - |
111 |
| -## Forms with nested objects |
112 |
| - |
113 |
| -Say that you have a nested object that you would want to send to your API |
114 |
| - |
115 |
| -```js |
116 |
| -const object = { foo: { bar: { baz: 'hi' } } }; |
117 |
| -``` |
118 |
| - |
119 |
| -```js |
120 |
| -const form: any = useAjvForm( |
121 |
| - { |
122 |
| - foo: { bar: { baz: '' } }, |
123 |
| - }, |
124 |
| - { |
125 |
| - type: 'object', |
126 |
| - properties: { |
127 |
| - foo: { |
128 |
| - type: 'object', |
129 |
| - properties: { |
130 |
| - bar: { |
131 |
| - type: 'object', |
132 |
| - required: ['baz'], |
133 |
| - properties: { |
134 |
| - baz: { |
135 |
| - type: 'string', |
136 |
| - minLength: 5, |
137 |
| - errorMessage: { |
138 |
| - minLength: 'Too short', |
139 |
| - }, |
140 |
| - }, |
141 |
| - }, |
142 |
| - }, |
143 |
| - }, |
144 |
| - }, |
145 |
| - }, |
146 |
| - }, |
147 |
| -); |
148 |
| -``` |
149 |
| - |
150 |
| -Normally, with most libraries out there, you would always get a flat object back, then you would have to "normalize" it before it's sent somewhere. |
151 |
| - |
152 |
| -With this library, that's a lot easier. |
153 |
| - |
154 |
| -Let's imagine that we have our own custom input |
155 |
| - |
156 |
| -```jsx |
157 |
| -const CustomInput = ({ form, name }) => { |
158 |
| - return ( |
159 |
| - <> |
160 |
| - <input |
161 |
| - type="text" |
162 |
| - name={name} |
163 |
| - value={form.state[name].value} |
164 |
| - onChange={(e) => form.setState({ [e.target.name]: e.target.value })} |
165 |
| - /> |
166 |
| - {form.state[name].error && <p>{form.state[name].error}</p>} |
167 |
| - </> |
168 |
| - ); |
169 |
| -}; |
170 |
| -``` |
171 |
| - |
172 |
| -```jsx |
173 |
| -<CustomInput form={form} name="foo.bar.baz" /> |
174 |
| -``` |
175 |
| - |
176 |
| -Simply pass the object path as the `name` prop and this library will generate the object for you. But not only that, validate it against the provided schema. |
0 commit comments