callbag-form
v0.3.0
Published
Framework agnostic form management with callbags
Downloads
4
Maintainers
Readme
callbag-form
Framework agnostic form management based on callbags
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