powerform

A powerful form model.

Usage no npm install needed!

<script type="module">
  import powerform from 'https://cdn.skypack.dev/powerform';
</script>

README

Build Status

Logo by Anand

Introduction

A tiny super portable form model which can be used in apps with or without frameworks like React.

Showcase

Vanilla JS

React

Mithril

Breaking changes

v4 introduces significant changes which are not backward compatible with v3. Please checkout the change log.

Installation

yarn

yarn add powerform

npm

npm install powerform

Quick walk-through

// 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.

// 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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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
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.

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().