Built-in validators

In this section we will discuss every built-in validator in detail.

NotEmpty

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

Empty

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

Equal

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

Max

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

Min

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


Choice

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

Pattern

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

Email

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

Phone

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

IsType

Primitive 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
}

Url

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

SameAs

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

Callback

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

Ajax

Primitive 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 the ValidationResult's valid flag will be true.

  • The request succeeded, and the value is invalid:
    In which case the ValidationResult's valid flag will be false.

  • The request failed to execute:
    In which case the ValidationResult's valid flag will be false and the error flag will be true with the related exception in errorDetail.

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 and message given in the factory.
    • if the status code is 2xx the value is considered valid.

Valid

Primitive 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

Invalid

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

And

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

Or

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

If

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

Compose

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

Container

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


Foreach

Container 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