Built-in validators
In this section we will discuss every built-in validator in detail.
NotEmptyPrimitive Sync
Check that the value is not empty.
// Factory prototype
NotEmpty(options?: ValidatorOptionsInterface|string)
// Usage
NotEmpty().validate('test') // ok
NotEmpty().validate('') // fail
NotEmpty().validate(' ') // ok
NotEmpty().validate([]) // fail
NotEmpty().validate({}) // fail
NotEmpty().validate(false) // ok
NotEmpty().validate(null) // fail
Argument | Description |
---|---|
An object (or a string to only define message ). |
EmptyPrimitive Sync
Check that the value is empty.
// Factory prototype
Empty(message?: string, type?: string)
// Usage
Empty().validate('test') // fail
Empty().validate('') // ok
Empty().validate(' ') // fail
Empty().validate([]) // ok
Empty().validate({}) // ok
Empty().validate(false) // fail
Empty().validate(null) // ok
Argument | Description |
---|---|
message | Custom error message. Default: 'This value must be empty.' . |
type | Custom error type. Default: 'empty' . |
EqualPrimitive Sync
Check that the value is equal to a static value.
// Factory prototype
Equal(value: Primitive, strict?: boolean, message?: string, type?: string)
// Usage
Equal('a').validate('a') // ok
Equal(true).validate('true') // fail
Equal(true, false).validate('true') // ok
Equal({a: 1, b: 2}]).validate({b: 2, a: 1}) // ok
Equal({a: 1, b: 2}]).validate({b: 2, a: 1, c: 3}) // fail
Equal([3, 4]).validate([4, 3]) // fail
Equal([3, 4]).validate([3, 4]) // ok
Argument | Description |
---|---|
value | The value to test equality with. |
strict | If false , cast the value being validated to match the type of the comparison value. Default: true . |
message | Custom error message. Default: 'The value is not what is expected.' . |
type | Custom error type. Default: 'equal' . |
MaxPrimitive Sync
Check if the number of elements counted in a value is greater or equal than a number.
Works with strings, numbers, arrays and objects. The type of comparison is determined by the type of the value to validate.
To distinguish between a string containing only a number (e.g. '12') and a number (e.g. 12) you can use the "treatAs" argument to force a cast.
// Factory prototype
Max(count: number, treatAs?: 'string'|'number'|'auto', message?: string|'auto', type?: string)
// Usage
Max(5).validate(3) // ok
Max(3).validate('Test') // fail
Max(5).validate('42') // ok
Max(5, 'number').validate('42') // fail
Max(2).validate(['a', 'b', 'c']) // fail
Max(5).validate({name: 'Paul'}) // ok
Argument | Description |
---|---|
count | The maximum count to accept. |
treatAs | Force the validated value to be casted as a string or number . If set to auto the type is untouched. |
message | Custom error message. If set to auto a different message is returned depending on the type of the value. If you add %count% to your message, it will be replaced by the number of elements counted in the value. |
type | Custom error type. Default: 'max' . |
MinPrimitive Sync
Check if the number of elements counted in a value is lesser or equal than a number.
This validator is the opposite of Max. Please check out its documentation as it's the exact same thing.
The condition is simply reversed from >=
to <=
.
ChoicePrimitive Sync
Check that the value is in a list of predefined choices.
// Factory prototype
Choice(choices: any[], message?: string, type?: string)
// Usage
Choice(['a', 'b']).validate('b') // ok
Choice(['a', 'b']).validate('b ') // fail
Choice([{attr1: 'v1', attr2: 'v2'}]).validate({attr2: 'v2', attr1: 'v1'}) // ok
Choice([[1, 2], [3, 4]]).validate([4, 3]) // fail
Choice([[1, 2], [3, 4]]).validate([3, 4]) // ok
Argument | Description |
---|---|
choices | Array of valid choices. |
message | Custom error message. Default: 'The value is not part of the expected choices.' . |
type | Custom error type. Default: 'choice' . |
PatternPrimitive Sync
Check that the value matches a RegExp
.
// Factory prototype
Pattern(pattern: RegExp, message?: string, type?: string)
// Usage
Pattern(/^[a-z]/).validate('abc') // ok
Pattern(/^[a-z]/).validate('0abc') // fail
Pattern(new RegExp("[a-z]+", "i")).validate('aBc') // ok
Argument | Description |
---|---|
pattern | A regex the value will have to match. |
message | Custom error message. Default: 'Invalid value.' . |
type | Custom error type. Default: 'pattern' . |
EmailPrimitive Sync
Check that the value is a valid email address.
// Factory prototype
Email(message?: string, type?: string)
// Usage
Email().validate('email@example.com') // ok
Email().validate('irstname+lastname@example.com') // ok
Email().validate('plaintext') // fail
Email().validate('Joe Smith <email@example.com>') // fail
Argument | Description |
---|---|
message | Custom error message. Default: 'Must be a valid email.' . |
type | Custom error type. Default: 'email' . |
PhonePrimitive Sync
Check that the value is a valid phone number.
// Factory prototype
Phone(message?: string, type?: string)
// Usage
Phone().validate('0689912549') // ok
Phone().validate('+33-6-79-91-25-49') // ok
Phone().validate('(555)-555-5555') // ok
Phone().validate('067 9 91 254 9') // fail
Argument | Description |
---|---|
message | Custom error message. Default: 'Must be a valid phone number.' . |
type | Custom error type. Default: 'phone' . |
IsTypePrimitive Sync
Check that the value matches a type.
// Factory prototype
IsType(target: Type, message?: string, type?: string)
// Usage
IsType(Type.String).validate('abc') // ok
IsType(Type.String).validate('2') // ok
IsType(Type.String).validate(2) // fail
IsType(Type.Number).validate('2') // fail
IsType(Type.Numeric).validate('2') // ok
IsType(Type.Number | Type.String).validate('2') // ok
IsType(Type.Object).validate([]) // ok
IsType(Type.Object).validate({}) // ok
IsType(Type.Array).validate({}) // fail
Argument | Description |
---|---|
target | Target type the value must comply with. |
message | Custom error message. Default: 'Invalid type of value. Expecting one of: %types%' . |
type | Custom error type. Default: 'is-type' . |
Click to see available types
enum Type {
String = 1,
Number = 2,
Numeric = 4,
Boolean = 8,
Object = 16,
Array = 32,
Symbol = 64,
Undefined = 128,
Null = 256
}
UrlPrimitive Sync
Check that the value is a valid url.
// Factory prototype
Url(message?: string, type?: string)
// Usage
Url().validate('example.com') // ok
Url().validate('http://www.site.com:8008') // ok
Url().validate('255.255.255.255') // ok
Url().validate('http://invalid.com/perl.cgi?key= | http://web-site.com/cgi-bin/perl.cgi?key1=value1&key2') // fail
Argument | Description |
---|---|
message | Custom error message. Default: 'Must be a valid url.' . |
type | Custom error type. Default: 'url' . |
SameAsPrimitive Sync
Check that the value is the same as the value of another part of the validation tree.
// Factory prototype
SameAs(path: string, message?: string, type?: string)
// Usage
Container({
password: And(NotEmpty(), Min(8)),
passwordConfirm: SameAs('/password')
})
Argument | Description |
---|---|
path | A path to other value to test with. The path can be relative (e.g.: ../another-prop ), or absolute (e.g.: /email ). More details here |
message | Custom error message. Default: 'The value must be the same as "%path%".' . |
type | Custom error type. Default: 'same-as' . |
CallbackPrimitive Sync or Async (depending on the callback)
Delegate the validation to a custom callback.
type ValidationCallback = (context: ValidationContext) => Promise<any>|ObservablePromiseInterface<any>|undefined;
// Factory prototype
Callback(callback: ValidationCallback)
// Usage
Callback((context: ValidationContext) => {
if (/* Custom condition */) {
context.result.addViolation('custom', 'Custom failure message.');
}
});
// Async example
Callback(async (context: ValidationContext) => {
if (!(await someAsyncCheck(context.value))) {
context.result.addViolation('custom', 'Failed asynchronously.');
}
});
Argument | Description |
---|---|
callback | The validation function that will be called when validating. The function can return a Promise (which is a shortcut for calling context.result.delayResponse(promise) manually). |
AjaxPrimitive Async
The Ajax validator delegates the validation logic to a remote server.
The configuration is divided in two parts:
- The setup of the request (
requestFactory
argument below) - The handling of the response (
responseHandler
argument below)
type RequestFactory = (value: any) => HttpRequest;
type ResponseHandler = (response: HttpResponse<any>, result: ValidationResult) => void;
// Factory prototype
Ajax(requestFactory: RequestFactory|HttpRequestFactoryConfig|string,
responseHandler?: ResponseHandler,
message?: string,
type?: string)
// Usage
// Will do a POST request on "https://your-domain.tld/is-email-available"
// with the JSON payload "{value: 'test@domain.tld'}".
Ajax('//is-email-available').validate('test@domain.tld')
Argument | Description |
---|---|
requestFactory | A HttpRequest object or a way to create one. More detail below. |
responseHandler | An optional method that will be called with the response. More detail here. |
message | Custom error message. |
type | Custom error type. |
Request setup
The Ajax validator uses the HttpService
to do the request. So a HttpRequest
object is required to make it work.
You have 4 ways of configuring the request:
- 1) You can give a
HttpRequest
object directly:
Ajax(request)
- 2) You can define a factory method that will be called when the validator is used:
Ajax((value: any /* The value being validated */): HttpRequest => {
// Do what you need and return a HttpRequest object.
})
- 3) You can give a configuration object that will be used to build the request:
// Here is the full object definition for reference
export interface HttpRequestFactoryConfig {
method?: HttpMethod,
url: string,
payload?: any,
payloadType?: symbol,
responseType?: symbol,
headers?: any,
timeout?: number|null,
retry?: number|null,
retryDelay?: number|'auto'|null,
priority?: number|null,
withCredentials?: boolean|null,
mimeType?: string|null,
extras?: any
}
// Most of it is optional, you can simply do:
Ajax({url: '//test.com'})
- 4) Or lastly, you can give a
string
that will be used as url. All other parameters will use default values:
Ajax('https://my-site.com/check-something')
Default values
When using the solutions 3 or 4, default parameters will be used where you don't define a value explicitly. Here are the defaults:
- method: default HTTP method is
POST
- payload: if the value being validated is an object (arrays are objects), it will be used as is. If not, it will be wrapped in an object with the key value:
{value: ...}
.
TIP
The payload encoding will depend on your configuration of the HttpService
. By default, the payload is encoded into JSON.
All the other parameters use the HttpService
's defaults. Please refer to the documentation for further details.
Handling the response
Each time a request is sent, there a three possible outcomes:
The request succeeded, and the value is valid:
In which case theValidationResult
'svalid
flag will betrue
.The request succeeded, and the value is invalid:
In which case theValidationResult
'svalid
flag will befalse
.The request failed to execute:
In which case theValidationResult
'svalid
flag will befalse
and theerror
flag will betrue
with the related exception inerrorDetail
.
To determine if the value passed the validation, there are two ways:
- 1) You can define a
responseHandler
callback that will be called when the response is received from the server:
Ajax(request, (response: HttpResponse<any>, result: ValidationResult) => {
if (!response.result.valid) {
result.addViolation('ajax', 'Custom error message.');
}
})
The callback takes the response as received from the HttpService
and the ValidationResult
so you can add violations if needed.
- 2) If no response handler is defined, a default handler is set.
Its behavior is very simple and based on the HTTP status code:
- if the status code is 5xx the validator is put on error.
- if the status code is NOT 2xx a violation is emitted using the default
type
andmessage
given in the factory. - if the status code is 2xx the value is considered valid.
ValidPrimitive Sync
A validator doing nothing. It will never create a violation.
// Factory prototype
Valid()
// Usage
Valid().validate('any value') // ok
Valid().validate(undefined) // ok
Valid().validate(null) // ok
Argument | Description |
---|---|
No argument |
InvalidPrimitive Sync
A validator that always fails.
// Factory prototype
Invalid(message?: string, type?: string)
// Usage
Invalid().validate('any value') // fail
Invalid('Custom error message.').validate(undefined) // fail
Invalid('Custom error', 'custom-type').validate(null) // fail
Argument | Description |
---|---|
message | Custom error message. Default: undefined . |
type | Custom error type. Default: 'invalid' . |
AndVirtual container Async if any child is async. Sync otherwise.
Execute each of the given validators sequentially until one of them fails.
This validator is a "virtual container", meaning its presence is invisible to the validation result. More info on the dedicated section.
TIP
If an asynchronous validator is encountered, it will wait for it to finish before executing the next one.
// Factory prototype
And(...validators: ValidatorInterface[])
// Usage
And(NotEmpty(), Min(5)).validate('') // fail
And(NotEmpty(), Min(5)).validate('Test') // fail
And(NotEmpty(), And(Min(2), Pattern(/^[a-z]+$/))).validate('abc') // ok
And(NotEmpty(), And(Min(2), Pattern(/^[a-z]+$/))).validate('Abc') // fail
Argument | Description |
---|---|
validators | Any number of validators to execute until one fails. |
OrVirtual container Async if any child is async. Sync otherwise.
Execute each of the given validators sequentially until one of them succeed.
This validator is a "virtual container", meaning its presence is invisible to the validation result. More info on the dedicated section.
TIP
If an asynchronous validator is encountered, it will wait for it to finish before executing the next one.
// Factory prototype
Or(...validators: ValidatorInterface[])
// Usage
Or(Empty(), Min(5)).validate('') // ok
Or(Empty(), Min(5)).validate('Test') // fail
Or(Empty(), Min(5)).validate('Test!') // ok
Argument | Description |
---|---|
validators | Any number of validators to execute until one succeeds. |
IfVirtual container Async if any child or the condition callback is async. Sync otherwise.
Execute each of the given validators sequentially if a condition verifies.
This validator is a "virtual container", meaning its presence is invisible to the validation result. More info on the dedicated section.
TIP
If an asynchronous validator is encountered, it will wait for it to finish before executing the next one.
type ConditionCallback = (context: ValidationContextInterface) => boolean|Promise<boolean>;
// Factory prototype
If(condition: ConditionCallback, ...validators: ValidatorInterface[])
// Usage
If(() => true, NotEmpty()).validate('') // fail
If(() => false, NotEmpty()).validate('') // ok
If((context: ValidationContextInterface) => {
// Do whatever test you need, like checking another value:
return !!context.getOtherValue('email');
}, NotEmpty()).validate('') // ok
If(() => {
return new Promise((resolve) => {
window.setTimeout(() => void resolve(true), 1000);
});
}, NotEmpty()).validate('') // wait for 1 second then fail
Argument | Description |
---|---|
condition | A callback returning true to execute the validators or false if nothing should be done. Can return a Promise<boolean> if necessary. |
validators | Any number of validators to execute if the condition verifies. |
ComposeVirtual container Async if any child is async. Sync otherwise.
Execute all the given validators in parallel.
This validator is a "virtual container", meaning its presence is invisible to the validation result. More info on the dedicated section.
TIP
All validators are executed immediately, even if some of them are asynchronous.
But the ValidationResult
will only resolve when all of them have finished their execution.
// Factory prototype
Compose(...validators: ValidatorInterface[])
// Usage
Compose(NotEmpty(), Min(5)).validate('') // fail with 2 violations
Compose(Ajax(...), Min(5)).validate('') // will execute both validators at the same time
Argument | Description |
---|---|
validators | Any number of validators to execute in parallel. |
ContainerContainer Async if any child is async. Sync otherwise.
First kind of container validator. It doesn't execute any validation logic itself but takes other validators to execute.
You can give it an object where each property is assigned to a validator:
// Factory prototype
Container(validators: ValidatorsCollection)
// Usage
const validator = Container({
name: NotEmpty(),
email: And(NotEmpty(), Email())
});
validator.validate({
name: null, // NotEmpty()
email: 'example@domain.tld' // And(NotEmpty(), Email())
})
or an array if you want to define different validators depending on the index of the item:
const validator = Container([
NotEmpty(),
Min(10)
]);
validator.validate([
'first item', // NotEmpty(),
'second item', // Min(10)
'third item' // No validator for this item
]);
WARNING
Do not confuse Container
(used with an array of validators) with Foreach
(here).
Container
will apply each validator to the item of the same index in the array being validated.
Foreach
on the other hand will apply all validators to each item of the array being validated.
ForeachContainer Async if any child is async. Sync otherwise.
Takes a validator as parameter and use it to validate every iterable item of the validated value.
// Factory prototype
Foreach(validator: ValidatorInterface)
// Usage
const validator = Foreach(NotEmpty());
validator.validate([
'a', // NotEmpty()
'b', // NotEmpty()
'c' // NotEmpty()
]);
It will also work with any iterable value:
const validator = Foreach(NotEmpty());
validator.validate({
firstName: 'John', // NotEmpty()
lastName: 'Doe', // NotEmpty()
email: 'john@doe.com' // NotEmpty()
});
// A string is iterable
Foreach(And(Min(1), Max(1))).validate('abc') // ok