powerform
Version:
A powerful form model.
522 lines (387 loc) • 11 kB
Markdown
[](https://travis-ci.org/ludbek/powerform)
<img src="https://user-images.githubusercontent.com/8296449/30893678-3e1702a8-a35f-11e7-8f6c-965ffe88cf40.png" width=400>
Logo by [Anand](https://www.behance.net/mukhiyaanad378)
## Introduction
A tiny super portable form model which can be used in apps with or without frameworks like [React](https://github.com/facebook/react).
## Showcase
[Vanilla JS](https://codesandbox.io/s/powerform-vanilla-js-ug2sx)
[React](https://codesandbox.io/s/powerform-react-17gqu)
[Mithril](https://codesandbox.io/s/powerform-mithril-pdrl1?file=/src/index.js)
## Breaking changes
v4 introduces significant changes which are not backward compatible with v3.
Please checkout the [change log](CHANGE_LOG.txt).
## Installation
### yarn
`yarn add powerform`
### npm
`npm install powerform`
## Quick walk-through
```javascript
// es6
import { powerform } from "powerform";
import { required, minLength, equalsTo } from "validatex";
const schema = {
username: required(true),
password: [required(true), minLength(8)],
confirmPassword: [required(true), equalsTo("password")],
};
const form = powerform(schema);
// assign values to fields
form.username.setData("ausername");
form.password.setData("apassword");
form.confirmPassword.setData("bpassword");
// per field validation
console.log(form.username.validate()) > true;
console.log(form.password.validate()) > true;
console.log(form.confirmPassword.validate()) > false;
console.log(form.confirmPassword.getError()) > "Passwords do not match.";
// validate all the fields at once
console.log(form.validate()) > false;
console.log(form.getError()) >
{
username: undefined,
password: undefined,
confirmPassword: "Password and confirmation does not match.",
};
```
## API
### Form
#### powerform(schema, config?: object)
Returns a form.
```javascript
// reusing the schema from walkthrough
const form = powerform(schema);
```
##### Config schema
```
{
data: object,
onChange(data: object, form: Form): function,
onError(error: object, form: Form): function,
stopOnError: boolean
}
```
##### Set initial values of field
Pass an object at `config.data` to set initial field values.
```javascript
const config = {
data: {
username: "a username",
password: "a password",
},
};
const form = powerform(schema, config);
console.log(form.username.getData()) > "a username";
console.log(form.password.getData()) > "a password";
```
##### Track changes in data and error
Changes to values and errors of fields can be tracked through `config.onChange` callback.
```javascript
const config = {
onChange: (data, form) => {
console.log(data);
},
onError: (error, form) => {
console.log(error);
},
};
const form = powerform(schema, config);
form.username.setData("a username") >
// logs data
{
username: "a username",
password: null,
confirmPassword: null,
};
form.password.validate() >
// logs changes to error
{
username: null,
password: "This field is required.",
confirmPassword: null,
};
```
##### Validate one field at a time
It is possible to stop validation as soon as one of the fields fails.
To enable this mode of validation set `config.stopOnError` to `true`.
One can control the order at which fields are validated by supplying `index` to fields.
```javascript
const loginSchema = {
password: {validator: required(true), index: 2}
username: {validator: required(true), index: 1}
}
const form = powerform(loginSchema, {stopOnError: true})
console.log(form.validate())
>> false
console.log(form.getError())
>> {username: "This field is required."}
```
#### form.setData(data: object)
Sets value of fields of a form.
```javascript
const form = powerform(schema);
let data = {
username: "a username",
password: "a password",
};
form.setData(data);
console.log(form.username.getData()) > "a username";
console.log(form.password.getData()) > "a password";
console.log(form.confirmPassword.getData()) > null;
```
#### form.getData()
Returns key value pair of fields and their corresponding values.
```javascript
const form = powerform(schema);
let data = {
username: "a username",
password: "a password",
};
form.setData(data);
console.log(form.getData()) >
{
username: "a username",
password: "a password",
confirmPassword: null,
};
```
#### form.getUpdates()
Returns key value pair of updated fields and their corresponding values.
The data it returns can be used for patching a resource over API.
```javascript
const userFormSchema = {
name: required(true),
address: required(true),
username: required(true),
};
const form = powerform(userFormSchema);
let data = {
name: "a name",
address: "an address",
};
form.setData(data);
console.log(form.getUpdates()) >
{
name: "a name",
address: "an address",
};
```
#### form.setError(errors: object)
Sets error of fields in a form.
```javascript
const form = powerform(schema);
const errors = {
username: "Invalid username.",
password: "Password is too common.",
};
form.setError(errors);
console.log(form.username.getError()) > "Invalid username.";
console.log(form.password.getError()) > "Password is too common.";
console.log(form.confirmPassword.getError()) > null;
```
#### form.getError()
Returns key value pair of fields and their corresponding errors.
```javascript
const form = powerform(schema);
form.password.setData("1234567");
form.confirmPassword.setData("12");
form.validate();
console.log(form.getError()) >
{
username: "This field is required.",
password: "This field must be at least 8 characters long.",
confirmPassword: "Passwords do not match.",
};
```
#### form.isDirty()
Returns `true` if value of one of the fields in a form has been updated.
Returns `false` if non of the fields has been updated.
```javascript
const form = powerform(schema);
console.log(form.isDirty()) > false;
form.username.setData("a username");
console.log(f.isDirty()) > true;
```
#### form.makePristine()
Sets initial value to current value in every fields.
```javascript
const form = powerform(schema);
form.username.setData("a username");
console.log(form.isDirty()) > true;
form.makePristine();
console.log(form.isDirty()) > false;
console.log(form.username.getData()) > "a username";
```
#### form.reset()
Resets all the fields of a form.
```javascript
const form = powerform(schema);
form.username.setData("a username");
form.password.setData("a password");
console.log(form.getData()) >
{
username: "a username",
password: "a password",
confirmPassword: null,
};
form.reset();
console.log(form.getData()) >
{
username: null,
password: null,
confirmPassword: null,
};
```
#### form.isValid()
Returns `true` if all fields of a form are valid.
Returns `false` if one of the fields in a form is invalid.
Unlike `form.validate()` it does not set the error.
```javascript
const form = powerform(schema);
form.password.setData("1234567");
console.log(form.isValid()) > false;
console.log(form.getError()) >
{
username: null,
password: null,
confirmPassword: null,
};
```
### Field
Every keys in a schema that is passed to `powerform` is turned into a Field. We do not need to directly instanciate it.
#### Field(config?: object| function | [function])
Creates and returns a field instance.
##### Config schema
```
{
validator: function | [function],
default?: any,
debounce?: number,
onChange(value: any, field: Field)?: function
onError(error: any, field: Field)?: function
}
```
##### Set default value
A field can have default value.
```javascript
const form = powerform({
username: { validator: required(true), default: "orange" },
});
console.log(form.username.getData()) > "orange";
```
##### Trance changes in value and error
Changes in value and error of a field can be tracked through `config.onChange` and `config.onError` callbacks.
```javascript
function logData(data, field) {
console.log('data: ', data)
}
function logError(data, field) {
console.log('error: ', error)
}
const form = powerform({
username: {
validator: required(true),
default: 'orange',
onChange: logData,
onError: logError
}
})
form.username.validate()
> "error: " "This field is required."
form.username.setData('orange')
> "data: " "orange"
form.username.validate()
> "error: " null
```
##### Debounce change in value
Changes in data can be debounced.
```javascript
const form = powerform({
username: {
validator: required(true),
default: 'orange',
onChange: logData,
onError: logError
}
})
form.username.setData("banana")
// after 1 second
> "data: " "banana"
```
#### Field.setData(value: any)
Sets field value.
```javascript
const form = powerform({
name: required(true),
});
form.name.setData("a name");
console.log(form.name.getData()) > "a name";
```
#### Field.getData()
Returns field value.
#### Field.modify(newValue: any, oldValue: any)
Modifies user's input value.
Example usage -
- capitalize user name as user types
- insert space or dash as user types card number
```javascript
const form = powerform({
name: {
validator: required(true),
modify(value) {
if (!value) return null;
return value.replace(/(?:^|\s)\S/g, (s) => s.toUpperCase());
},
},
});
form.name.setData("first last");
console.log(form.name.getData()) > "First Last";
```
#### Field.clean(value: any)
Cleans the value.
`form.getData()` uses this method to get clean data.
It is useful for situations where value in a view should be different to
the value in stores.
```javascript
const form = powerform({
card: {
validator: required(true),
modify(newVal, oldVal) {
return newVal.length === 16
? newCard
.split("-")
.join("")
.replace(/(\d{4})/g, "$1-")
.replace(/(.)$/, "")
: newCard
.split("-")
.join("")
.replace(/(\d{4})/g, "$1-");
},
clean(value) {
return card.split("-").join("");
},
},
});
form.card.setData("1111222233334444");
console.log(form.card.getData()) > "1111-2222-3333-4444";
console.log(form.getData()) > { card: "1111222233334444" };
```
### field.validate(value: any, allValues: object)
#### field.isValid()
Returns `true` or `false` based upon the validity.
#### field.setError(error: string)
Sets field error.
#### field.getError()
Returns field error.
Call this method after validating the field.
#### field.isDirty()
Returns `true` if value of a field is changed else returns `false`.
#### field.makePristine()
Marks a field to be untouched.
It sets current value as initial value.
#### field.reset()
It resets the field.
Sets initial value as current value.
#### field.setAndValidate(value: any)
Sets and validates a field. It internally calls `Field.setData()` and `Field.validate()`.