Skip to content
This repository has been archived by the owner on Aug 25, 2020. It is now read-only.

Commit

Permalink
Merged Version 0.8.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Nevoss authored Apr 1, 2019
2 parents 89bad6e + ed7e273 commit 05c815b
Show file tree
Hide file tree
Showing 22 changed files with 581 additions and 342 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default {
},
methods: {
async submit() {
const { response } = await this.form.submit(form => axios.post('some-url', form.values()))
const { response } = await this.form.$submit(form => axios.post('some-url', form.$values()))
}
},
}
Expand Down
12 changes: 6 additions & 6 deletions docs/guide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ export default {
methods: {
async submit() {
try {
const {response} = await this.form.submit(form =>
axios.post('https://example.com/form', form.values())
const {response} = await this.form.$submit(form =>
axios.post('https://example.com/form', form.$values())
)
} catch (e) {}
},
Expand Down Expand Up @@ -110,17 +110,17 @@ export default {
methods: {
async submit() {
try {
const response = await this.form.submit(form =>
axios.post('https://example.com/form', form.values())
const response = await this.form.$submit(form =>
axios.post('https://example.com/form', form.$values())
)
} catch (e) {}
},
},
}
```

The Form `submit` method accept a function as it first arguments, the function must return a promise. to explore about more information of
how you can use the `submit` method take a look at [Form submission](/guide/form-submission.md) section.
The Form `$submit` method accept a function as it first arguments, the function must return a promise. to explore about more information of
how you can use the `$submit` method take a look at [Form submission](/guide/form-submission.md) section.

Last thing to do is to bind the `submit` method that we created to the form itself

Expand Down
36 changes: 18 additions & 18 deletions docs/guide/field-events.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
# Field events

To get the full power of the library it is recommended to bind 3 event methods to your fields:
`fieldChanged`, `fieldBlurred` and `fieldFocused`.
`$fieldChanged`, `$fieldBlurred` and `$fieldFocused`.
in this section we will cover why do you need those method and how to use them.

## Field Focused

`fieldFocused` method is useful for 2 things:
`$fieldFocused` method is useful for 2 things:

- To track which field is on focus
- To track which field is touched

```vue
<template>
<div>
<input type="text" v-model="form.name" @focus="form.fieldFocused('name')" />
<input type="text" v-model="form.name" @focus="form.$fieldFocused('name')" />
<span v-if="form.$onFocus === 'name'"> Name is on focus </span>
<span v-if="form.isTouched('name')"> Name is touched </span>
<span v-if="form.$touched.has('name')"> Name is touched </span>
</div>
</template>
```

As you can see every time `@focus` event is triggered on `name` field, `fieldFocused` method will be invoked with `name` as its' argument.
then the of `$onFocus` will become `name` and the field also will be marked as `touched`.
As you can see every time `@focus` event is triggered on `name` field, `$fieldFocused` method will be invoked with `name` as its' argument.
then the of `$onFocus` will become `name` and the field also will be marked as touched.

::: warning
Make sure to read `fieldBlurred` method explanation when you are using `fieldFocused` method to track `$onFocus` property.
Make sure to read `$fieldBlurred` method explanation when you are using `$fieldFocused` method to track `$onFocus` property.
:::

## Field Blurred

`fieldBlurred` method is useful for 2 things:
`$fieldBlurred` method is useful for 2 things:

- It will release `$onFocus` - if you will bind `fieldFocused` event without bind `fieldBlurred` event,
the field will remain `$onFocus` until you will call `fieldFocused` again.
- It will release `$onFocus` - if you will bind `EfieldFocused` event without bind `$fieldBlurred` event,
the field will remain `$onFocus` until you will call `$fieldFocused` again.
- It will validate the field if declared in the [options](/guide/options)

```vue
<template>
<div>
<input type="text" v-model="form.name" @blur="form.fieldBlurred('name')" />
<input type="text" v-model="form.name" @blur="form.$fieldBlurred('name')" />
</div>
</template>
```

## Field Changed

`fieldChange` is a general method for 2 possible events,
`$fieldChange` is a general method for 2 possible events,
for some elements `onChange` event will be suitable and for another `onInput`.

The method is useful for 2 things:
Expand All @@ -57,8 +57,8 @@ The method is useful for 2 things:
```vue
<template>
<div>
<input type="text" v-model="form.name" @input="form.fieldChanged('name')" />
<select v-model="form.type" @change="form.fieldChanged('type')">
<input type="text" v-model="form.name" @input="form.$fieldChanged('name')" />
<select v-model="form.type" @change="form.$fieldChanged('type')">
<!-- options.... -->
</select>
</div>
Expand All @@ -79,13 +79,13 @@ const form = new Form({

form.name = 'Nevo +'

form.isDirty('name') // returns true
form.isDirty('last_name') // returns false
form.$isDirty('name') // returns true
form.$isDirty('last_name') // returns false

form.isDirty() // returns true
form.$isDirty() // returns true
```

When you pass an argument to the `isDirty` method it checks the field key that you passed to it, but if you call the
When you pass an argument to the `$isDirty` method it checks the field key that you passed to it, but if you call the
method without arguments it will check the whole form and then return `true` if at least one field is `dirty`.


Expand Down
30 changes: 15 additions & 15 deletions docs/guide/form-submission.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export default {
methods: {
async submit() {
try {
const { response, form } = await this.form.submit(form =>
axios.post('https://example.com/form', form.values())
const { response, form } = await this.form.$submit(form =>
axios.post('https://example.com/form', form.$values())
)
} catch ({ error, form }) {}
},
Expand All @@ -37,42 +37,42 @@ export default {
</script>
```

In this code snippet we are using 'axios' but `submit` method accept any method that returns a `Promise`.
In this code snippet we are using 'axios' but `$submit` method accept any method that returns a `Promise`.

On successful submission the `submit` method resolves an object with 2 properties.
On successful submission the `$submit` method resolves an object with 2 properties.

- `response` - holds the resolved data from your `submit` method.
- `response` - holds the resolved data from your `$submit` method.
- `form` - holds the whole form object

On failure the `submit` method throws an exception with 2 properties object.
On failure the `$submit` method throws an exception with 2 properties object.

- `error` - holds the exception that was throw (or rejected) from the `submit` method promise.
- `error` - holds the exception that was throw (or rejected) from the `$submit` method promise.
- `form` - holds the whole form object.

## Files and JSON strings

There are 2 methods that can help you format your fields values:

- The first method, `valuesAsFormData` is useful in cases when you need to submit a form with a file in it, the common way to do so is to send the form with a `Content-Type` header: `multipart/form-data`,
- The first method, `$valuesAsFormData` is useful in cases when you need to submit a form with a file in it, the common way to do so is to send the form with a `Content-Type` header: `multipart/form-data`,
and sending the form values as `FormData` object. this is where the method comes into action:

```js
form.submit(() => axios.post('https://example.com/form', form.valuesAsFormData(), {
form.$submit(() => axios.post('https://example.com/form', form.$valuesAsFormData(), {
headers: { 'Content-Type': 'multipart/form-data' }
}))
```

- The second one,`valuesAsJson` is useful for some HTTP clients that require a raw JSON as a request body.
the method is just a shortcut for `JSON.stringify(form.values())`
- The second one,`$valuesAsJson` is useful for some HTTP clients that require a raw JSON as a request body.
the method is just a shortcut for `JSON.stringify(form.$values())`


## Why do I need `submit`?
## Why do I need `$submit`?

It seems like `submit` method just uses the callback you provide and nothing more, but in fact `submit` is doing little bit more:
It seems like `$submit` method just uses the callback you provide and nothing more, but in fact `$submit` is doing little bit more:

- `$submitting` property become `true` when the user is sending the `Form` and turn to `false` when the submission is finished.
- By default the form is validating itself before any submission and do not send the request if the validation failed. (can be changed via [options](/guide/options)).
- By default the form clears the `errors`, the field `values` and the `touched` array after submission. (can be changed via [options](/guide/options)).
- By default the form clears the `$errors`, the field `values` and the `$touched` array after submission. (can be changed via [options](/guide/options)).

In the next section there is an explanation about [interceptors](/guide/interceptors), this is another reason you should
use the `submit` method.
use the `$submit` method.
12 changes: 6 additions & 6 deletions docs/guide/interceptors.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Before we started, this module inspired by [axios](https://github.com/axios), so

## What `interceptors` are?

`interceptors` are basically methods that are injected into the submission process, some of them comes before the submission and some of them comes after.
the library letting creates your custom `interceptors`. here are some basic examples.
`$interceptors` are basically methods that are injected into the submission process, some of them comes before the submission and some of them comes after.
the library letting creates your custom `$interceptors`. here are some basic examples.

Let say your server side endpoint returns an errors on submission and you wants to `fill` the `$error` property with those errors,
Let say your server side endpoint returns an errors on submission and you wants to `fill` the `$errors` property with those errors,
the simple solution is to doing something like that:

```js
Expand All @@ -17,7 +17,7 @@ export default {
methods: {
async submit() {
try {
await this.form.submit(
await this.form.$submit(
() => axios(
// ...
)
Expand All @@ -32,7 +32,7 @@ export default {
}
```

This behavior can be repeat from form to form, to prevent this duplication we can use `interceptors`.
This behavior can be repeat from form to form, to prevent this duplication we can use `$interceptors`.

```js
// /form/Form.js
Expand All @@ -51,7 +51,7 @@ Form.defaults.interceptors.submissionComplete.use(
export default {
methods: {
async submit() {
await this.form.submit(
await this.form.$submit(
() => axios(
// ...
)
Expand Down
8 changes: 4 additions & 4 deletions docs/guide/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const form = new Form(
```js
const form = new Form({ name: null })

form.assignOptions({
form.$assignOptions({
// override options object
})

Expand All @@ -49,7 +49,7 @@ Form.defaults.options.validation.onFieldChanged = true // change specific defaul
## Default options

This deceleration snippet was taken from the code itself. you can overview the whole
`options` object and the default values of it.
`$options` object and the default values of it.

```js
export default {
Expand Down Expand Up @@ -115,6 +115,6 @@ export default {

::: warning

- `validation.onFieldChange` - will work only if the [field event `fieldChange`](/guide/field-events.md) was bounded to the field element.
- `validation.onFieldBlurred` - will work only if the [field event `fieldBlurred`](/guide/field-events.md) was bounded to the field element.
- `validation.onFieldChange` - will work only if the [field event `$fieldChange`](/guide/field-events.md) was bounded to the field element.
- `validation.onFieldBlurred` - will work only if the [field event `$fieldBlurred`](/guide/field-events.md) was bounded to the field element.
:::
88 changes: 85 additions & 3 deletions docs/guide/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ there are the 2 "shapes" of validation rule:
By default the validation runs on submission. you can tweak out the [options](/guide/options) and make your validation runs on field input event or on field blurred event
and also you can call the validation manually:

- `form.validate()` - will validate the whole form
- `form.validate('name')` - will validate only `name` field
- `form.$validate()` - will validate the whole form
- `form.$validate('name')` - will validate only `name` field

check out the [options](/guide/options) before starting to use those methods.
:::
Expand Down Expand Up @@ -140,9 +140,91 @@ return a rejected promise with `RuleValidationError`
One thing to understand, you must reject with **`RuleValidationError`**! otherwise the error will bubble up.
:::

You can use `form.isValidating('email')` In case that your `Promise` base validating take some time, the function will
You can use `form.$isValidating('email')` In case that your `Promise` base validating take some time, the function will
return `true` if the `Promise` base validation is still running and `false` if not.

## Dynamic validation

Dynamic validation is useful when there is a field validation that depend on another field, to solve this problem there are 2 options.

1. **This is the recommended way**, create a function that wraps the validation rule (object or function) inside another validation rule:
```js
// This example demonstrates a case that a validation rule is an object and not a function

// In your validation file
export const userRuleIf = (conditionCallback, rule) => {
return {
passes: (field, form) => {
if (!conditionCallback(field, form)) {
return true
}

return rule.passes(field, form)
},
message: rule.message,
}
}

// In your vue file
import { Form } from 'form-wrapper-js'
import { required, useRuleIf } from '@/form/validation.js'

export default {
data() {
return {
form: new Form({
is_developer: false,
programing_languages: {
value: [],
rules: [
userRuleIf((field, form) => form.is_developer === true, required),
]
}
})
}
},
// ...Your vue stuff
}
```

Of course, you can extend this function and make it more flexible, one way to do so is to support also function validation rules
and not only objects.

2. Another way is to rebuild the whole rules for the specific field, you can do so with the method `form.$rules.buildFieldRules('fieldName', [rule, rule])`.
this option is less performance because there is some process that the library does to build those rules into something that the library can use.
but sometimes there are cases that your rule depend on data that lives outside the scope of the Form.

```js
// In your vue file
import { Form } from 'form-wrapper-js'
import { required, useRuleIf } from '@/form/validation.js'

export default {
data() {
return {
is_developer: false,
form: new Form({
programing_languages: {
value: [],
rules: []
}
})
}
},
methods: {
switchIsDeveloper(state) {
this.is_developer = state

this.form.$rules.buildFieldRules(
'programing_languages',
state ? [required] : []
)
}
}
// ...Your vue stuff
}
```

## Errors

The errors collector will collect errors each time validating a specific field or the whole form,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "form-wrapper-js",
"version": "0.7.4",
"version": "0.8.0",
"description": "JS abstraction for forms",
"main": "dist/index.js",
"module": "dist/index.es.js",
Expand Down
Loading

0 comments on commit 05c815b

Please sign in to comment.