callbag-form
TypeScript icon, indicating that this package has built-in type declarations

0.3.0 • Public • Published

callbag-form

Framework agnostic form management based on callbags

tests coverage version


npm i callbag-form

callbag-form provides a simple method for managing forms and validation in TypeScript / JavaScript. Provides a state containing the form data, sources emitting form validity, error report, and whether form data has changed.

import form, { required, isEmail, isStrongPassword, isSame, isTrue } from 'callbag-form'


const registration = form({
  name: ['', { required }],                                 // 👉 name is required
  email: ['', { required, isEmail }],                       // 👉 email is required and must be an email
  password: ['', isStrongPassword()],                       // 👉 password must be a strong password
  passwordRepeat: ['', { match: isSame(f => f?.password) }] // 👉 password repeat must be the same with password
  agreeToS: [false, { isTrue }]                             // 👉 must have agreed to tos 
})

// 👉 read/write form data
registration.data.get()
registration.data.set({ ... })

// 👉 form data is a callbage
pipe(registration.data, subscribe(console.log))

// 👉 form data is a state
registration.data.sub('email').set(...)
pipe(registration.data.sub('agreeToS'), subscribe(console.log))

// 👉 track validity
pipe(registration.valid, subscribe(console.log))

// 👉 check if email has errors
pipe(registration.errors, map(e => e.email.hasErrors))

// 👉 check if email format has issues
pipe(registration.errors, map(e => e.email.isEmail))

// 👉 check if password has a special character (validator included in `isStrongPassword()`):
pipe(registration.errors, map(e => e.password.hasSpecialChar))

// 👉 check if password-repeat matches:
pipe(registration.errors, map(e => e.passwordRepeat.match))

Checkout a real-life example using callbag-jsx.


👉 You can also provide your own source of data:

const registration = form(source, {
  name: { required },
  email: { required, isEmail },
  password: isStrongPassword(),
  passwordRepeat: { match: isSame(f => f?.password)) },
  agreeToS: { isTrue }
})



Installation

Install via NPM (or Yarn):

npm i callbag-form

Or use via CDNs:

<script type="module">
  import form from 'https://unpkg.com/callbag-form/dist/bundles/callbag-form.es.min.js'
  
  // ...
</script>



Validators

Validators in callbag-form are simple functions which return true or false with given value:

export function required(t) {
  return isNotNull(t) && (
    (t as any).length === undefined
    || (t as any).length > 0
  )
}

👉 Validators are assumed to be synchronous and computationally inexpensive. Computationally expensive and/or async validators are rare and so can be accounted for specifically.


Validators can also take into account the whole form data:

export function isSame(selector) {
  return (value, form) => value === selector(form)
}

callbag-form comes with a handful of validators that are commonly used:

required            // 👉 checks if value is not null and not empty string / array
isTrue              // 👉 checks if value is true
doesMatch(regex)    // 👉 checks if value matches given regexp
isUrl               // 👉 checks if value is a proper URL (https only, regexp check)
isEmail             // 👉 checks if value is a proper email (regexp check)
hasMinLength(n)     // 👉 checks if value (string or array) has at least length of n
isSame(selector)    // 👉 checks if value equals return result of the selector (which is provided the form data)
hasUpperCase        // 👉 checks if value has at-least one upper case character
hasLowerCase        // 👉 checks if value has at-least one lower case character
hasDigit            // 👉 checks if value has at-least one digit character
hasSpecialChar      // 👉 checks if value has at-least one special character

There is also isStrongPassword(), which provides a bundle of validation functions:

export function isStrongPassword() {
  return {
    required,
    hasUpperCase,
    hasLowerCase,
    hasDigit,
    hasSpecialChar,
    length: hasMinLength(8)
  }
}



Change Tracking

Forms can also track whether the data has actually changed. Enable that by calling .track():

form.track()

Then set checkpoints using .checkpoint() method (for example when data is synced with server):

form.checkpoint()

The form data will be now compared to the last checkpoint:

// 👉 check whether form data has changed since last checkpoint:
pipe(form.changed, subscribe(console.log))

Don't forget to cleanup the form tracking subscription. You can do that either by calling .dispose():

form.dispose()

Or by calling the callback returned by .track():

const dispose = form.track()

// ...

dispose()

This means you can easily track forms in callbag-jsx using tracking:

export function MyComponent(_, renderer) {

  const myForm = form(...)
  this.track(myForm.track())

  // ...
  
  return <> ... </>
}



Contribution

There are no contribution guidelines or issue templates currently, so just be nice (and also note that this is REALLY early stage). Useful commands for development / testing:

git clone https://github.com/loreanvictor/callbag-form.git
npm i                   # --> install dependencies
npm start               # --> run `samples/index.tsx` on `localhost:3000`
npm test                # --> run all tests
npm run cov:view        # --> run tests and display the code coverage report



Package Sidebar

Install

npm i callbag-form

Weekly Downloads

1

Version

0.3.0

License

MIT

Unpacked Size

157 kB

Total Files

56

Last publish

Collaborators

  • lorean.victor