Skip to content
This repository was archived by the owner on Apr 9, 2025. It is now read-only.

Commit 94ad27a

Browse files
author
Daniel Requejo
committed
🧱 Add build function and documentation
1 parent 67892dd commit 94ad27a

File tree

5 files changed

+110
-4
lines changed

5 files changed

+110
-4
lines changed

docs/.vitepress/config.cts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export default defineConfig({
9292
link: '/api/use-form-handler/modified-values',
9393
},
9494
{ text: 'register', link: '/api/use-form-handler/register' },
95+
{ text: 'build', link: '/api/use-form-handler/build' },
9596
{ text: 'resetField', link: '/api/use-form-handler/reset-field' },
9697
{ text: 'resetForm', link: '/api/use-form-handler/reset-form' },
9798
{ text: 'setError', link: '/api/use-form-handler/set-error' },

docs/api/use-form-handler/build.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# build
2+
3+
Builds a form based on the configuration passed, to leave a cleaner template and provide better readability over the whole form setup.
4+
5+
## Demo
6+
7+
Coming soon...
8+
9+
## Usage
10+
11+
### Build complex form fields and improve readability
12+
13+
```vue
14+
<template>
15+
<form @submit.prevent="() => handleSubmit(successFn, errorFn)">
16+
<input type="text" v-bind="form.name" />
17+
<input type="text" v-bind="form.email" />
18+
<input type="text" v-bind="form.password" />
19+
<input type="text" v-bind="form.passwordConfirmation" />
20+
<button type="submit">Submit</button>
21+
</form>
22+
</template>
23+
<script setup lang="ts">
24+
import { useFormHandler } from 'vue-form-handler'
25+
26+
const successFn = (result: Record<string, any>) => { console.log(result) }
27+
const errorFn = (result: Record<string, string | undefined>) => { console.warn(result) }
28+
const { build, handleSubmit, values, formState } = useFormHandler()
29+
30+
const form = build({
31+
name: {
32+
required: true,
33+
pattern: {
34+
value: /^[a-zA-Z]+$/,
35+
message: 'Only letters are allowed'
36+
}
37+
},
38+
email: {
39+
required: true,
40+
pattern: {
41+
value: /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/,
42+
message: 'Please enter a valid email'
43+
}
44+
},
45+
password: {
46+
required: true,
47+
pattern: {
48+
value: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/,
49+
message: 'Password must contain at least 8 characters, one uppercase, one lowercase and one number'
50+
}
51+
},
52+
passwordConfirmation: {
53+
required: true,
54+
pattern: {
55+
value: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/,
56+
message: 'Password must contain at least 8 characters, one uppercase, one lowercase and one number'
57+
},
58+
validate: {
59+
match: (value: string) => value === values.password || 'Passwords do not match'
60+
}
61+
}
62+
})
63+
</script>
64+
```
65+
66+
Notice how the template looks much cleaner with this approach, and this helps us to achieve better readability and is less confusing since we bind directly pieces of a form to each component/field on the template.
67+
68+
## Type Declarations
69+
70+
```ts
71+
export interface Build<T = Record<string, RegisterOptions>> {
72+
(configuration: T | Ref<T> | ComputedRef<T>): ComputedRef<
73+
Record<keyof T, RegisterReturn>
74+
>
75+
}
76+
```

docs/api/use-form-handler/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ Using the `always` validationMode will have a more significant impact on perform
153153
- [handleSubmit](/api/use-form-handler/handle-submit)
154154
- [modifiedValues](/api/use-form-handler/modified-values)
155155
- [register](/api/use-form-handler/register)
156+
- [build](/api/use-form-handler/build)
156157
- [resetField](/api/use-form-handler/reset-field)
157158
- [resetForm](/api/use-form-handler/reset-form)
158159
- [setError](/api/use-form-handler/set-error)
@@ -187,6 +188,7 @@ export interface FormHandlerReturn {
187188
handleSubmit: HandleSubmit
188189
modifiedValues: ModifiedValues
189190
register: Register
191+
register: Build
190192
resetField: ResetField
191193
resetForm: ResetForm
192194
setError: SetError

src/types/formHandler.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ComputedRef, Ref } from 'vue'
2-
import { RegisterOptions, Register } from './register'
2+
import { RegisterOptions, Register, RegisterReturn } from './register'
33

44
export interface FormState {
55
/** Boolean holding the dirty state of the form */
@@ -77,6 +77,12 @@ export type HandleSubmit = (
7777
errorFn?: HandleSubmitErrorFn
7878
) => void
7979

80+
export interface Build<T = Record<string, RegisterOptions>> {
81+
(configuration: T | Ref<T> | ComputedRef<T>): ComputedRef<
82+
Record<keyof T, RegisterReturn>
83+
>
84+
}
85+
8086
export interface InterceptorParams {
8187
/** Name of the field that is currently about to be set*/
8288
name: string
@@ -159,6 +165,9 @@ export interface FormHandlerReturn {
159165
/** Method to register a field and make it interact with the current form */
160166
register: Register
161167

168+
/** Method to build a form configuration */
169+
build: Build
170+
162171
/** Function to reset a field */
163172
resetField: ResetField
164173

src/useFormHandler.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Build } from './types/formHandler'
12
import { NativeValidations } from './types/validations'
23
import { DEFAULT_FIELD_VALUE } from './constants'
34
import {
@@ -23,8 +24,10 @@ import {
2324
ValidationsConfiguration,
2425
Unregister,
2526
FieldReference,
27+
RegisterOptions,
28+
RegisterReturn,
2629
} from './types'
27-
import { reactive, readonly, unref, watch } from '@vue/runtime-core'
30+
import { computed, reactive, readonly, unref, watch } from '@vue/runtime-core'
2831
import { isEqual } from 'lodash-es'
2932
import {
3033
getNativeFieldValue,
@@ -59,7 +62,7 @@ export const useFormHandler: UseFormHandler = ({
5962
const _getDefault = (name: string): any =>
6063
_refs[name]?._defaultValue ?? getDefaultFieldValue(_refs[name]?.ref)
6164
const _getInitial = (name: string): any =>
62-
unref(initialValues)?.[name] ?? _getDefault(name)
65+
(unref(initialValues) as Record<string, any>)?.[name] ?? _getDefault(name)
6366
const _initControl: InitControl = (name, options) => {
6467
const needsReset = options.disabled && _refs[name] && !_refs[name]._disabled
6568
_refs[name] = {
@@ -76,7 +79,11 @@ export const useFormHandler: UseFormHandler = ({
7679
unregister(name)
7780
return
7881
}
79-
if (initialValues[name] === undefined && values[name] === undefined) {
82+
if (
83+
(!initialValues ||
84+
(unref(initialValues) as Record<string, any>)?.[name] === undefined) &&
85+
values[name] === undefined
86+
) {
8087
values[name] = _getDefault(name)
8188
}
8289
}
@@ -289,6 +296,16 @@ export const useFormHandler: UseFormHandler = ({
289296
}
290297
}
291298

299+
const build: Build = (configuration) => {
300+
const staticConfig = unref(configuration) as Record<string, RegisterOptions>
301+
return computed(() =>
302+
Object.keys(staticConfig).reduce((acc, key) => {
303+
acc[key] = register(key, staticConfig[key])
304+
return acc
305+
}, {} as Record<string, RegisterReturn>)
306+
)
307+
}
308+
292309
const isValidForm: IsValidForm = async () => {
293310
if (validate) {
294311
return await validate(values)
@@ -322,6 +339,7 @@ export const useFormHandler: UseFormHandler = ({
322339
handleSubmit,
323340
modifiedValues,
324341
register,
342+
build,
325343
resetField,
326344
resetForm,
327345
setError,

0 commit comments

Comments
 (0)