validx
Validation library for MobX.
Install
npm install --save validx
Table of Contents
Why?
We want to reactively display validation issues in our UI when using MobX. You can use
any (non-DOM) validation library, but then you still need to make it reactive.
ValidX is built for MobX and is easy to use, yet
powerful enough to add any validation you'd like.
Examples
See the TypeScript example and Babel example for runnable examples (in Node).
API documentation
The ValidationContext
The meat of the library is the validation context. To create one, you can either use
import { ValidationContext } from 'validx'
const validation = new ValidationContext()
Or use the factory function
import { validationContext } from 'validx'
const validation = validationContext()
The properties on the context are reactive (observables/computeds powered by MobX).
validate()
Given an object and a schema, validates the object and returns itself.
validate()
is a MobX action
.
Calling it will populate the errors
property with any validation errors
found on the object
There are multiple ways to use validate()
, see Bound ValidationContext.
import { validationContext, required, pattern } from 'validx'
const validation = validationContext()
validation.reset()
const schema = {
name: [
required({ msg: 'Name is required' })
],
email: [
required({ msg: 'Email is required' }),
pattern({ pattern: 'email', msg: 'Not a valid email' })
]
}
validation.validate({
name: '',
email: ''
}, schema)
Now that we have validated our object, we can pull the errors
from the context.
console.log(validation.isValid)
console.log(validation.errors.name)
console.log(validation.errors.email)
To validate again, we need to reset the context and then call validate.
validation.reset().validate({
name: 'Jeff',
email: 'test'
}, schema)
console.log(validation.isValid)
console.log(validation.errors.name)
console.log(validation.errors.email)
Let's see what the errors are like when we
log them after resetting.
validation.reset()
console.log(validation.isValid)
console.log(validation.errors.name)
console.log(validation.errors.email)
They are undefined because we don't know
what fields will be validated yet.
validation.validate({
name: 'Jeff',
email: 'test'
}, schema)
console.log(validation.isValid)
console.log(validation.errors.name)
console.log(validation.errors.email)
reset()
Resets the internal state of the context. You usually use this before
starting a new validation. reset()
is a MobX action
.
const validation = validationContext()
validation.validate({ name: '' }, {
name: [required()]
})
console.log(validation.errors.name)
validation.reset()
console.log(validation.errors.name)
Use case: sharing a validation context in a class hierarchy.
class Element {
@observable label = ''
validation = validationContext(this)
@action validate () {
this.validation.validate({
label: [required({ msg: 'Label required' })]
})
}
}
class TextElement extends Element {
@observable placeholder = ''
@action validate () {
this.validation.reset().validate({
placeholder: [required({ msg: 'Placeholder required' })]
})
super.validate()
}
}
const textElement = new TextElement()
textElement.validate()
console.log(textElement.validation.errors)
textElement.label = 'First name'
textElement.validate()
console.log(textElement.validation.errors)
addErrors()
If you at some point want to add errors without calling validate, this
is how to do it. addErrors()
is a MobX action
.
const obj = {}
const validation = validationContext(obj, {
})
if (usernameIsTaken) {
validation.addErrors({
username: ['Username is taken']
})
}
console.log(validation.errors.username)
getErrors()
Safer way to get errors for a field rather than using errors.field
,
as this will return an empty array in case there are no errors.
const validation = validationContext()
validation.addErrors({ name: ['Not cool'] })
validation.getErrors('name')
validation.reset()
validation.getErrors('name')
getError()
Convenience method for getErrors('field')[0]
.
Returns undefined
if the error is not found.
const validation = validationContext()
validation.addErrors({ name: ['Not cool'] })
validation.getError('name')
validation.reset()
validation.getError('name')
clearErrors()
Clear errors for a single field, instead of reseting the whole context.
const validation = validationContext()
validation.addErrors({ name: ['Not cool'], language: ['Must be JS'] })
validation.getError('name')
validation.clearErrors('name')
validation.getError('name')
validation.getError('language')
errors
A MobX computed
map of field -> errors. When validate
discovers validation errors, it
puts them in here.
If a field has not been validated, or the context has just been reset, there
will be no keys.
const validation = validationContext(obj, {
name: [required()]
})
console.log(validation.errors)
validation.validate()
console.log(validation.errors)
validation.validate()
isValid
A MobX computed
property that determines whether the context
has any errors or not.
const validation = validationContext()
console.log(validation.isValid)
validation.validate({ }, { name: [required()] })
console.log(validation.isValid)
Validators
Validators are just plain functions that take an object
with the rule configuration as a parameter and returns
either true for success, false for failure, or a string
for a failure with a specific message.
const validation = validationContext()
const schema = {
age: [
required({ msg: 'Age is required' }),
(opts) => opts.value >= 13 || 'Must be 13 years or older'
]
}
validation.validate({
age: 8
}, schema)
console.log(validation.errors.age)
Built-in validators
required
Takes a string (error message) or an object in the form of { required: boolean, msg: string }
.
If required === false
, the validator will always return true.
{
firstName: [required()],
lastName: [required('Last name, please?')],
phoneNumber: [
required({
msg: 'Please enter your number so we can send you those notifications',
required: this.getSmsNotifications,
})
]
}
pattern
Let's you specify a named pattern or your own regex. Supports simple and config signatures.
Named patterns:
'email'
(uses email-validator
)'url'
(uses is-url
)
Example:
{
email: [pattern('email')],
homepage: [pattern('url', 'Not a valid URL, come on!')],
bio: [pattern(/javascript/i, 'Sorry - no JS, no job.')],
twitterHandle: [
pattern({
pattern: /^@/,
msg: 'Twitter handles start with an @'
})
]
}
func
If you dislike the boolean || 'message'
approach to custom validators, you can use func
.
Example:
{
knownLibraries: [
(opts) => opts.value.includes('react') || 'Sorry, only React devs here!',
func(
(opts) => opts.value.includes('react'),
'Sorry, only React devs here!'
)
]
}
Bound ValidationContext
By passing either 1 or 2 parameters to validationContext
, you can "pre-bind" it
to an object and a schema.
const obj = { name: '' }
const validation = validationContext()
validation.validate(obj, {
name: [required()]
})
const obj = { name: '' }
const validation = validationContext(obj)
validation.validate({
name: [required()]
})
const obj = { name: '' }
const validation = validationContext(obj, {
name: [required()]
})
validation.validate()
Author
Jeff Hansen - @Jeffijoe