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

feat: reset fields with specific values #44

Merged
merged 7 commits into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![npm](https://img.shields.io/npm/v/vue3-form-validation)](https://www.npmjs.com/package/vue3-form-validation)

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

- :milky_way: **Written in TypeScript**
- :ocean: **Dynamic Form support**
Expand Down Expand Up @@ -34,12 +34,11 @@ const {

- `formData`
- **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:

```ts
const formData = {
Expand Down Expand Up @@ -67,7 +66,7 @@ const formDataWithRules = {
};
```

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:

```ts
type Field<T> = {
Expand All @@ -76,7 +75,7 @@ type Field<T> = {
};
```

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:

```ts
type FormData = {
Expand All @@ -92,15 +91,15 @@ const { ... } = useValidation<FormData>({ ... });

- `form`
- **Type** - `object`
- **Description** - Transformed `formData` object.
- **Description** - Transformed form data object.
- `submitting`
- **Type** - `Ref<boolean>`
- **Description** - `True` during validation after calling `validateFields`.
- `errors`
- **Type** - `ComputedRef<string[]>`
- **Description** - Array of all current validation error messages.

`Form` is a reactive object with identical structure as the `formData` input.
`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:

```ts
Expand All @@ -124,14 +123,14 @@ type Form = {
```

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 fields an their use case:
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`
- **Type** - `string[]`
- **Description** - Array of validation error messages.
Expand All @@ -140,25 +139,27 @@ description of all the fields an their use case:
- **Description** - `True` while at least one rule is validating.
- `$onBlur`
- **Type** - `function`
- **Description** - Function which will mark this Form 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.
- **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.

### `useValidation` exposes the following methods:

- `validateFields() -> Promise`
- **Description** - Validate all Fields.
- **Returns** - A `Promise` which will reject if there are validation errors, and resolve with the `formData` otherwise.
- `resetFields() -> void`
- **Description** - Reset all 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.

## Writing Rules

Expand Down Expand Up @@ -211,7 +212,7 @@ const isNameTaken = name =>
## 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 write an issue or open a pull request, for more information about the project 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).

## License
Expand Down
10 changes: 5 additions & 5 deletions main/Form.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { computed, reactive, ref, unref } from 'vue';
import { SimpleRule, Rule } from './composable/useValidation';
import { SimpleRule, Rule } from './composition/useValidation';
import FormField from './FormField';
import { PromiseCancel, tryGet, trySet } from './utils';

Expand Down Expand Up @@ -101,9 +101,9 @@ export default class Form {
});
}

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

Expand All @@ -121,9 +121,9 @@ export default class Form {
}
}

const settledResult = await Promise.allSettled(promises);
const settledResults = await Promise.allSettled(promises);

for (const result of settledResult) {
for (const result of settledResults) {
if (result.status === 'rejected') {
return true;
}
Expand Down
28 changes: 15 additions & 13 deletions main/FormField.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { computed, isRef, reactive, ref } from 'vue';
import { Rule } from './composable/useValidation';
import { Rule } from './composition/useValidation';

const notNull = <T>(value: T | null): value is T => value !== null;

export default class FormField {
private errors: (string | null)[];

rulesValidating = ref(0);
modelValue: ReturnType<typeof ref> | ReturnType<typeof reactive>;
private initialModelValue: unknown;
touched = false;
rulesValidating = ref(0);

private errors: (string | null)[];
private initialModelValue: unknown;

constructor(rules: Rule[], modelValue: unknown) {
this.errors = reactive(rules.map(() => null));
Expand Down Expand Up @@ -42,16 +42,18 @@ export default class FormField {
return computed(() => this.rulesValidating.value > 0);
}

reset() {
reset(toDefaultValues: boolean) {
this.touched = false;

if (isRef(this.modelValue)) {
this.modelValue.value = this.initialModelValue;
} else {
Object.assign(this.modelValue, this.initialModelValue);
this.initialModelValue = JSON.parse(
JSON.stringify(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)
);
}
}

Object.assign(
Expand Down
Loading