🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

vue3-form-validation

Package Overview
Dependencies
Maintainers
1
Versions
59
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

vue3-form-validation - npm Package Compare versions

Comparing version
3.0.4
to
3.0.5
+1
dist/composition/useUid.d.ts
export default function useUid(): number;
let uid = 1;
export default function useUid() {
return uid++;
}
import { Ref, ComputedRef, UnwrapRef } from 'vue';
export declare type SimpleRule<T = any> = (value: T) => any;
export declare type KeyedRule<T = any> = {
key: string;
rule: SimpleRule<T>;
};
export declare type Rule<T = any> = SimpleRule<T> | KeyedRule<T>;
export declare type Field<TValue> = {
$value: TValue extends Ref ? TValue | UnwrapRef<TValue> : TValue extends any[] ? TValue : TValue extends Record<string, unknown> ? RefUnref<TValue> : Ref<TValue> | TValue;
$rules?: Rule<UnwrapRef<TValue>>[];
};
export declare type TransformedField<T> = {
$uid: number;
$value: T;
$errors: string[];
$validating: boolean;
$onBlur(): void;
};
export declare type RefUnref<T extends Record<string, unknown>> = {
[K in keyof T]: T[K] extends Ref ? T[K] | UnwrapRef<T[K]> : T[K] extends any[] ? T[K] : T[K] extends Record<string, unknown> ? RefUnref<T[K]> : Ref<T[K]> | T[K];
};
export declare type TransformedFormData<T extends object> = T extends any ? {
[K in keyof T]: T[K] extends {
$value: infer TValue;
} ? TransformedField<UnwrapRef<TValue>> : T[K] extends Record<string, unknown> | any[] ? TransformedFormData<T[K]> : T[K];
} : never;
export declare type FormData<T extends object> = T extends any ? {
[K in keyof T]: T[K] extends {
$value: infer TValue;
} ? UnwrapRef<TValue> : T[K] extends Record<string, unknown> | any[] ? FormData<T[K]> : T[K];
} : never;
export declare type Keys = readonly (string | number)[];
export declare type DeepIndex<T, Ks extends Keys> = Ks extends [
infer First,
...infer Rest
] ? First extends keyof T ? Rest extends Keys ? DeepIndex<T[First], Rest> : undefined : undefined : T;
declare type UseValidation<T extends object> = {
form: TransformedFormData<T>;
submitting: Ref<boolean>;
errors: ComputedRef<string[]>;
validateFields(): Promise<FormData<T>>;
resetFields(formData?: FormData<T>): void;
add<Ks extends Keys>(pathToArray: readonly [...Ks], value: DeepIndex<T, Ks> extends Array<infer TArray> ? TArray : never): void;
remove<Ks extends Keys>(pathToArray: readonly [...Ks], index: DeepIndex<T, Ks> extends any[] ? number : never): void;
};
/**
*
* @param formData The structure of your Form Data.
* @description
* Vue composition function for Form Validation.
* @docs
* https://github.com/JensDll/vue3-form-validation
* @typescript
* For better type inference, consider defining the structure
* of your `formData` upfront and pass it as the generic parameter `T`:
* ```
* type FormData = {
* name: Field<string>,
* email: Field<string>,
* password: Field<string>
* }
*
* const { ... } = useValidation<FormData>({ ... })
* ```
*/
export declare function useValidation<T extends object>(formData: T): UseValidation<T>;
export {};
import { reactive } from 'vue';
import Form from '../Form';
import { cleanupForm, getResultFormData, path, PromiseCancel, resetFields, transformFormData } from '../utils';
/**
*
* @param formData The structure of your Form Data.
* @description
* Vue composition function for Form Validation.
* @docs
* https://github.com/JensDll/vue3-form-validation
* @typescript
* For better type inference, consider defining the structure
* of your `formData` upfront and pass it as the generic parameter `T`:
* ```
* type FormData = {
* name: Field<string>,
* email: Field<string>,
* password: Field<string>
* }
*
* const { ... } = useValidation<FormData>({ ... })
* ```
*/
export function useValidation(formData) {
const form = new Form();
const promiseCancel = new PromiseCancel();
transformFormData(form, formData);
const transformedFormData = reactive(formData);
return {
form: transformedFormData,
submitting: form.submitting,
errors: form.getErrors(),
async validateFields() {
form.submitting.value = true;
const resultFormData = {};
getResultFormData(transformedFormData, resultFormData);
const hasError = await promiseCancel.race(form.validateAll());
form.submitting.value = false;
if (hasError) {
throw void 0;
}
return resultFormData;
},
resetFields(formData) {
if (form.submitting.value) {
promiseCancel.cancelResolve(true);
}
if (formData) {
form.resetFields(false);
resetFields(transformedFormData, formData);
}
else {
form.resetFields();
}
},
add(pathToArray, value) {
const xs = path(pathToArray, transformedFormData);
if (Array.isArray(xs)) {
transformFormData(form, value);
xs.push(value);
}
},
remove(pathToArray, index) {
const xs = path(pathToArray, transformedFormData);
if (Array.isArray(xs)) {
const deleted = xs.splice(index, 1);
deleted.forEach(deleted => cleanupForm(form, deleted));
}
}
};
}
import Form from '../../Form';
export declare function transformFormData(form: Form, formData: any): void;
export declare function resetFields(transformedFormData: any, formData: any): void;
export declare function cleanupForm(form: Form, formData: any): void;
export declare function getResultFormData(formData: any, resultFormData: any): void;
import { isReactive, watch } from 'vue';
import useUid from '../../composition/useUid';
const isField = (field) => typeof field === 'object' ? '$value' in field : false;
const isTransformedField = (field) => typeof field === 'object'
? '$uid' in field &&
'$value' in field &&
'$errors' in field &&
'$validating' in field
: false;
export function transformFormData(form, formData) {
Object.entries(formData).forEach(([key, value]) => {
var _a;
if (isField(value)) {
const uid = useUid();
const formField = form.registerField(uid, (_a = value.$rules) !== null && _a !== void 0 ? _a : [], value.$value);
watch(formField.modelValue, () => {
if (formField.touched) {
form.validate(uid);
}
});
formData[key] = {
$uid: uid,
$value: formField.modelValue,
$errors: formField.getErrors(),
$validating: formField.validating(),
async $onBlur() {
if (!formField.touched) {
formField.touched = true;
await form.validate(uid);
}
}
};
return;
}
if (typeof value === 'object') {
transformFormData(form, value);
}
});
}
export function resetFields(transformedFormData, formData) {
Object.entries(transformedFormData).forEach(([key, value]) => {
if (isTransformedField(value)) {
if (isReactive(value.$value) && !Array.isArray(value.$value)) {
Object.assign(value.$value, formData[key]);
}
else {
value.$value = formData[key];
}
return;
}
if (typeof value === 'object') {
resetFields(value, formData[key]);
}
});
}
export function cleanupForm(form, formData) {
Object.values(formData).forEach(value => {
if (isTransformedField(value)) {
form.onDelete(value.$uid);
return;
}
if (typeof value === 'object') {
cleanupForm(form, value);
}
});
}
export function getResultFormData(formData, resultFormData) {
Object.entries(formData).forEach(([key, value]) => {
if (isTransformedField(value)) {
resultFormData[key] =
typeof value.$value === 'object'
? JSON.parse(JSON.stringify(value.$value))
: value.$value;
return;
}
if (typeof value == 'object') {
resultFormData[key] = {};
}
else {
resultFormData[key] = value;
return;
}
if (Array.isArray(value)) {
resultFormData[key] = [];
}
getResultFormData(value, resultFormData[key]);
});
}
+2
-2

@@ -1,2 +0,2 @@

import { Rule } from './composable/useValidation';
import { Rule } from './composition/useValidation';
import FormField from './FormField';

@@ -14,3 +14,3 @@ declare type ValidateResult = void | string;

getErrors(): import("vue").ComputedRef<string[]>;
resetFields(): void;
resetFields(toDefaultValues?: boolean): void;
validateAll(): Promise<boolean>;

@@ -17,0 +17,0 @@ validate(uid: number): Promise<PromiseSettledResult<ValidateResult>[]>;

@@ -59,5 +59,5 @@ import { computed, reactive, ref, unref } from 'vue';

}
resetFields() {
resetFields(toDefaultValues = true) {
for (const { formField } of this.simpleValidators.values()) {
formField.reset();
formField.reset(toDefaultValues);
}

@@ -76,4 +76,4 @@ }

}
const settledResult = await Promise.allSettled(promises);
for (const result of settledResult) {
const settledResults = await Promise.allSettled(promises);
for (const result of settledResults) {
if (result.status === 'rejected') {

@@ -80,0 +80,0 @@ return true;

import { reactive, ref } from 'vue';
import { Rule } from './composable/useValidation';
import { Rule } from './composition/useValidation';
export default class FormField {
modelValue: ReturnType<typeof ref> | ReturnType<typeof reactive>;
touched: boolean;
rulesValidating: import("vue").Ref<number>;
private errors;
rulesValidating: import("vue").Ref<number>;
modelValue: ReturnType<typeof ref> | ReturnType<typeof reactive>;
private initialModelValue;
touched: boolean;
constructor(rules: Rule[], modelValue: unknown);

@@ -13,3 +13,3 @@ setError(ruleNumber: number, error: string | null): void;

validating(): import("vue").ComputedRef<boolean>;
reset(): void;
reset(toDefaultValues: boolean): void;
}

@@ -5,4 +5,4 @@ import { computed, isRef, reactive, ref } from 'vue';

constructor(rules, modelValue) {
this.touched = false;
this.rulesValidating = ref(0);
this.touched = false;
this.errors = reactive(rules.map(() => null));

@@ -33,13 +33,15 @@ if (isRef(modelValue)) {

}
reset() {
reset(toDefaultValues) {
this.touched = false;
if (isRef(this.modelValue)) {
this.modelValue.value = this.initialModelValue;
if (toDefaultValues) {
if (isRef(this.modelValue)) {
this.modelValue.value = this.initialModelValue;
}
else {
Object.assign(this.modelValue, this.initialModelValue);
this.initialModelValue = JSON.parse(JSON.stringify(this.initialModelValue));
}
}
else {
Object.assign(this.modelValue, this.initialModelValue);
this.initialModelValue = JSON.parse(JSON.stringify(this.initialModelValue));
}
Object.assign(this.errors, this.errors.map(() => null));
}
}

@@ -1,2 +0,2 @@

export { useValidation } from './composable/useValidation';
export type { Field, Rule, KeyedRule, SimpleRule } from './composable/useValidation';
export { useValidation } from './composition/useValidation';
export type { Field, Rule, KeyedRule, SimpleRule } from './composition/useValidation';

@@ -1,1 +0,1 @@

export { useValidation } from './composable/useValidation';
export { useValidation } from './composition/useValidation';

@@ -5,1 +5,2 @@ export { trySet } from './map/trySet';

export { PromiseCancel } from './promise-cancel/PromiseCancel';
export * from './helper/helper';

@@ -5,1 +5,2 @@ export { trySet } from './map/trySet';

export { PromiseCancel } from './promise-cancel/PromiseCancel';
export * from './helper/helper';
{
"name": "vue3-form-validation",
"version": "3.0.4",
"version": "3.0.5",
"description": "Vue composition function for Form Validation",

@@ -41,25 +41,25 @@ "author": {

"@types/jest": "^26.0.20",
"@types/node": "^14.14.27",
"@typescript-eslint/eslint-plugin": "^4.15.0",
"@typescript-eslint/parser": "^4.15.0",
"@vitejs/plugin-vue": "^1.0.6",
"@vue/compiler-sfc": "^3.0.5",
"@types/node": "^14.14.31",
"@typescript-eslint/eslint-plugin": "^4.16.0",
"@typescript-eslint/parser": "^4.16.0",
"@vitejs/plugin-vue": "^1.1.5",
"@vue/compiler-sfc": "^3.0.7",
"autoprefixer": "^10.2.4",
"eslint": "^7.18.0",
"eslint-config-prettier": "^7.2.0",
"eslint": "^7.21.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-vue": "^7.4.1",
"husky": "^5.0.9",
"husky": "^5.1.2",
"jest": "^26.6.3",
"lint-staged": "^10.5.3",
"pinst": "^2.1.4",
"pinst": "^2.1.6",
"postcss": "^8.2.6",
"prettier": "^2.2.1",
"tailwindcss": "^2.0.3",
"ts-jest": "^26.5.1",
"ts-jest": "^26.5.2",
"ts-node": "^9.1.1",
"tsd": "^0.14.0",
"typescript": "^4.1.5",
"vite": "^2.0.0-beta.69",
"vue": "^3.0.5",
"vue-router": "^4.0.3"
"typescript": "^4.2.2",
"vite": "^2.0.4",
"vue": "^3.0.7",
"vue-router": "^4.0.4"
},

@@ -66,0 +66,0 @@ "prettier": {

+44
-28

@@ -5,3 +5,3 @@ # Form Validation for Vue 3

Opinionated Vue composition function for Form Validation.
Vue composition function for Form Validation.

@@ -38,8 +38,7 @@ - :milky_way: **Written in TypeScript**

- **Type** - `object`
- **Required** - `true`
- **Description** - The structure of your `formData`.
- **Description** - The structure of your form data.
The `formData` object has a structure that is similar to any other object you would write for `v-model` data binding. The only difference being that together with every value you can provide rules to display validation errors.
The form data object has a structure that is similar to any other object you would write for `v-model` data binding. The only difference being that together with every value you can provide rules to display validation errors.
Let's look at an example how the structure of some `formData` object can be converted to an object with the addition of rules:
Let's look at an example how the structure of some form data object can be converted to an object with the addition of rules:

@@ -72,3 +71,3 @@ ```ts

The `formData` object can contain arrays and can be deeply nested. At the leaf level, the object should contain Form Fields whose simplified type definition looks like the following:
The form data object can contain arrays and can be deeply nested. At the leaf level, the object should contain fields whose simplified type definition looks like the following:

@@ -82,3 +81,3 @@ ```ts

To get better type inference while writing the `useValidation` function, it's recommended to define the structure of your `formData` upfront and pass it as the generic parameter `T`. The type for the example above is pretty straightforward:
To get better type inference while writing the `useValidation` function, it's recommended to define the structure of your data upfront and pass it as the generic parameter `T`. The type for the example above is pretty straightforward:

@@ -91,2 +90,4 @@ ```ts

};
const { ... } = useValidation<FormData>({ ... });
```

@@ -98,3 +99,3 @@

- **Type** - `object`
- **Description** - Transformed `formData` object.
- **Description** - Transformed form data object.
- `submitting`

@@ -107,3 +108,4 @@ - **Type** - `Ref<boolean>`

`Form` is a reactive object with identical structure as the `formData` input, but with added metadata to every Form Field.
`Form` is a reactive object with identical structure as the form data input.
Every object with a `$value` property will be converted to an object of the following form:

@@ -118,5 +120,8 @@ ```ts

};
```
// The type of form in the example above would therefore be
const form: {
Given the structure of the previous example, this will result in the following type:
```ts
type Form = {
name: TransformedField<string>;

@@ -128,10 +133,11 @@ email: TransformedField<string>;

As you may have noticed, all of the properties are prefixed with the `$` symbol, which is to distinguish them from other properties but also to avoid naming conflicts.
As you may have noticed, all of the properties are prefixed with the `$` symbol, which is to distinguish them from other properties but also to avoid naming conflicts. Below is a
description of all the properties and their use case:
- `$uid`
- **Type** - `number`
- **Description** - Unique identifier of the Form Field. For dynamic Forms this can be used as the `key` attribute in `v-for`.
- **Description** - Unique identifier of the field. For dynamic forms this can be used as the `key` attribute in `v-for`.
- `$value`
- **Type** - `T`
- **Description** - The `modelValue` of the Form Field which is meant to be used together with `v-model`.
- **Description** - The `modelValue` of the field, which is meant to be used together with `v-model`.
- `$errors`

@@ -145,3 +151,3 @@ - **Type** - `string[]`

- **Type** - `function`
- **Description** - Function which will mark this Form Field as touched. When a Form Field has been touched it will validate all it's rules after every input. Before it will not do any validation.
- **Description** - Function which will mark this field as touched. When a field has been touched, it will validate all it's rules after every input. Before it will not do any validation.

@@ -151,16 +157,18 @@ ### `useValidation` exposes the following methods:

- `validateFields() -> Promise`
- **Description** - Validate all Form Fields.
- **Returns** - A `Promise` which will reject if there are validation errors, and resolve with the `formData` otherwise.
- `resetFields() -> void`
- **Description** - Reset all Form Fields to their original values.
- **Description** - Validate all fields.
- **Returns** - A `Promise` which will reject if there are validation errors, and resolve with the form data otherwise.
- `resetFields(formData?: object) -> void`
- **Description** - Reset all fields to their original value, or pass an object to set specific values. Check out the [Sandbox](https://codesandbox.io/s/vue-3-form-validation-demo-7mp4z?file=/src/views/LoginForm.vue) for usage examples.
- **Parameters**
- `formData?` - Values to use.
- `add(pathToArray: (string | number)[], value: any) -> void`
- **Description** - Utility function for writing dynamic Forms.
- **Description** - Utility function for writing dynamic forms.
- **Parameters**
- `pathToArray` - Tuple representing the path to an array in the `formData`.
- `pathToArray` - Tuple representing the path to an array in the form data.
- `value` - The value that will be pushed to the array at the given path.
- `remove(pathToArray: (string | number)[], index: number) -> void`
- **Description** - Utility function for writing dynamic Forms.
- **Description** - Utility function for writing dynamic forms.
- **Parameters**
- `pathToArray` - Tuple representing the path to an array in the `formData`.
- `index` - Array index that will be remove.
- `pathToArray` - Tuple representing the path to an array in the form data.
- `index` - Array index which will be remove.

@@ -180,6 +188,10 @@ ## Writing Rules

Keyed rules that share the same `key` will be executed together, this can be useful in a situation where rules are dependent on another. For example the `Password` and `Repeat Password` fields in a [Login Form](https://codesandbox.io/s/vue-3-form-validation-demo-7mp4z?file=/src/views/LoginForm.vue).
Keyed rules that share the same `key` will be executed together. This can be useful in a situation where rules are dependent on another, such as the `Password` and `Repeat Password` fields in a [Login Form](https://codesandbox.io/s/vue-3-form-validation-demo-7mp4z?file=/src/views/LoginForm.vue).
Rules will always be called with the latest `modelValue`, to determine if a call should result in an error, it will check if the rule's return value is of type `string`.
This allows you to write many rules in one line:
> To prevent overly aggressive error messages, keyed rules will only be called
> after all Fields with connected rules have been touched.
Because of the way the [logical operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#logical_operators) work in JavaScript, many basic rules can be written in one line:
```ts

@@ -193,3 +205,3 @@ const required = value => !value && 'This field is required';

Async rules allow you to perform network requests, for example checking if a username exists in the database:
Async rules allow you to perform network requests, for instance checking if a username exists in the database. Same rules apply as for simple rules, `resolve` or `reject` with a string if the validation fails:

@@ -209,6 +221,10 @@ ```ts

## Troubleshooting
- If you encounter errors while building, you may have to install a TypeScript **version >= 4.1**
## Contributing
If you find problems or if you have use cases that you think are not easy to achieve with the current API, please let me know :+1:
Feel free to file an issue or open a pull request, for more information checkout the
Feel free to write an issue or open a pull request, for more information about the project check out the
[contributing guideline](https://github.com/JensD98/vue3-form-validation/blob/master/.github/contributing.md).

@@ -215,0 +231,0 @@

export default function useUid(): number;
let uid = 1;
export default function useUid() {
return uid++;
}
import { Ref, ComputedRef, UnwrapRef } from 'vue';
import Form from '../Form';
export declare type SimpleRule<T = any> = (value: T) => any;
export declare type KeyedRule<T = any> = {
key: string;
rule: SimpleRule<T>;
};
export declare type Rule<T = any> = SimpleRule<T> | KeyedRule<T>;
export declare type Field<TValue> = {
$value: TValue extends Ref ? TValue | UnwrapRef<TValue> : TValue extends any[] ? TValue : TValue extends Record<string, unknown> ? RefUnref<TValue> : Ref<TValue> | TValue;
$rules?: Rule<UnwrapRef<TValue>>[];
};
export declare type TransformedField<T> = {
$uid: number;
$value: T;
$errors: string[];
$validating: boolean;
$onBlur(): void;
};
export declare type RefUnref<T extends Record<string, unknown>> = {
[K in keyof T]: T[K] extends Ref ? T[K] | UnwrapRef<T[K]> : T[K] extends any[] ? T[K] : T[K] extends Record<string, unknown> ? RefUnref<T[K]> : Ref<T[K]> | T[K];
};
export declare type TransformedFormData<T extends object> = T extends any ? {
[K in keyof T]: T[K] extends {
$value: infer TValue;
} ? TransformedField<UnwrapRef<TValue>> : T[K] extends Record<string, unknown> | any[] ? TransformedFormData<T[K]> : T[K];
} : never;
export declare type FormData<T extends object> = T extends any ? {
[K in keyof T]: T[K] extends {
$value: infer TValue;
} ? UnwrapRef<TValue> : T[K] extends Record<string, unknown> | any[] ? FormData<T[K]> : T[K];
} : never;
export declare type Keys = readonly (string | number)[];
export declare type DeepIndex<T, Ks extends Keys> = Ks extends [
infer First,
...infer Rest
] ? First extends keyof T ? Rest extends Keys ? DeepIndex<T[First], Rest> : undefined : undefined : T;
export declare function transformFormData(form: Form, formData: any): void;
export declare function cleanupForm(form: Form, formData: any): void;
export declare function getResultFormData(formData: any, resultFormData: any): void;
declare type UseValidation<T extends object> = {
form: TransformedFormData<T>;
submitting: Ref<boolean>;
errors: ComputedRef<string[]>;
validateFields(): Promise<FormData<T>>;
resetFields(): void;
add<Ks extends Keys>(pathToArray: readonly [...Ks], value: DeepIndex<T, Ks> extends Array<infer TArray> ? TArray : never): void;
remove<Ks extends Keys>(pathToArray: readonly [...Ks], index: DeepIndex<T, Ks> extends any[] ? number : never): void;
};
/**
*
* @param formData The structure of your Form Data.
* @description
* Vue composition function for Form Validation.
* @docs
* https://github.com/JensDll/vue3-form-validation
* @typescript
* For better type inference, consider defining the structure
* of your `formData` upfront and pass it as the generic parameter `T`:
* ```
* type FormData = {
* name: Field<string>,
* email: Field<string>,
* password: Field<string>
* }
*
* const { ... } = useValidation<FormData>({ ... })
* ```
*/
export declare function useValidation<T extends object>(formData: T): UseValidation<T>;
export {};
import { reactive, watch } from 'vue';
import useUid from './useUid';
import Form from '../Form';
import { path, PromiseCancel } from '../utils';
const isField = (field) => typeof field === 'object' ? '$value' in field : false;
const isTransformedField = (field) => typeof field === 'object'
? '$uid' in field &&
'$value' in field &&
'$errors' in field &&
'$validating' in field
: false;
export function transformFormData(form, formData) {
Object.entries(formData).forEach(([key, value]) => {
var _a;
if (isField(value)) {
const uid = useUid();
const formField = form.registerField(uid, (_a = value.$rules) !== null && _a !== void 0 ? _a : [], value.$value);
formData[key] = reactive({
$uid: uid,
$value: formField.modelValue,
$errors: formField.getErrors(),
$validating: formField.validating(),
async $onBlur() {
if (!formField.touched) {
formField.touched = true;
await form.validate(uid);
}
}
});
watch(formField.modelValue, () => {
if (formField.touched) {
form.validate(uid);
}
});
return;
}
if (typeof value === 'object') {
transformFormData(form, value);
}
});
}
export function cleanupForm(form, formData) {
Object.values(formData).forEach(value => {
if (isTransformedField(value)) {
form.onDelete(value.$uid);
return;
}
if (typeof value === 'object') {
cleanupForm(form, value);
}
});
}
export function getResultFormData(formData, resultFormData) {
Object.entries(formData).forEach(([key, value]) => {
if (isTransformedField(value)) {
resultFormData[key] =
typeof value.$value === 'object'
? JSON.parse(JSON.stringify(value.$value))
: value.$value;
return;
}
if (typeof value == 'object') {
resultFormData[key] = {};
}
else {
resultFormData[key] = value;
return;
}
if (Array.isArray(value)) {
resultFormData[key] = [];
}
getResultFormData(value, resultFormData[key]);
});
}
/**
*
* @param formData The structure of your Form Data.
* @description
* Vue composition function for Form Validation.
* @docs
* https://github.com/JensDll/vue3-form-validation
* @typescript
* For better type inference, consider defining the structure
* of your `formData` upfront and pass it as the generic parameter `T`:
* ```
* type FormData = {
* name: Field<string>,
* email: Field<string>,
* password: Field<string>
* }
*
* const { ... } = useValidation<FormData>({ ... })
* ```
*/
export function useValidation(formData) {
const form = new Form();
const promiseCancel = new PromiseCancel();
transformFormData(form, formData);
const transformedFormData = reactive(formData);
return {
form: transformedFormData,
submitting: form.submitting,
errors: form.getErrors(),
async validateFields() {
form.submitting.value = true;
const resultFormData = {};
getResultFormData(transformedFormData, resultFormData);
const hasError = await promiseCancel.race(form.validateAll());
form.submitting.value = false;
if (hasError) {
throw undefined;
}
return resultFormData;
},
async resetFields() {
if (form.submitting.value) {
promiseCancel.cancelResolve(true);
}
form.resetFields();
},
add(pathToArray, value) {
const xs = path(pathToArray, transformedFormData);
if (Array.isArray(xs)) {
transformFormData(form, value);
xs.push(value);
}
},
remove(pathToArray, index) {
const xs = path(pathToArray, transformedFormData);
if (Array.isArray(xs)) {
const deleted = xs.splice(index, 1);
deleted.forEach(deleted => cleanupForm(form, deleted));
}
}
};
}