Control Validators

Anton Moiseev
Angular Notes
Published in
2 min readOct 29, 2015

There is Validators class in Angular consisting of static methods used for form validation. Although all these methods are supposed to work with Controls they have different signatures and implemented a little bit differently — some accept a single Control parameter and return error object (e.g. Validators.required) others may accept arbitrary number of parameters and return a function (e.g. Validators.minLength):

export class Validators {

static required(control: Control): {[key: string]: boolean} {
//...
}
static minLength(minLength: number): Function {
return (control: Control): {[key: string]: any} => {
//...
}
}
}

It might be not immediately obvious why it is so, but the reason is actually trivial. Let’s consider these two examples above.

Validators.required needs only current Control’s value to answer the question whether a value is present or not. However Validators.minLength needs to compare Control’s value with another value. Well, where should we get that another value from?! It cannot be hardcoded inside the validator because it’s specific for a particular form field. Apparently this value should be externalized as a parameter so developers can specify it. But if we take a look at the Control class implementation we’ll see 100% of validators invoked with exactly the same parameter — Control instance:

export class AbstractControl {
updateValidity({onlySelf}: {onlySelf?: boolean} = {}): void {
this._errors = this.validator(this); //<- only Control is passed
//...
}
}

So by the time a validator function is invoked it should already know this external parameter. Experienced JavaScript developers know where I’m leading to — closures.

“Closure is a function call with strings attached.” — Yakov Fain

That’s exactly what Validators.minLength does — it creates a closure that remembers the minLength parameter. The returned function becomes a validator that in turn is invoked by Control class. If we compare how we use Validators.required and Validators.minLength it becomes even more apparent:

var control = new Control('',
Validators.compose[
Validators.required, // pass required itself
Validators.minLength(5) // pass a closure returned by minLength
]
);

In case of Validators.required we pass the method itself, in case of Validators.minLength we pass a closure returned by the method. So in both cases the functions that are actually passed to the Control’s constructor have the same signature and used by Control in exactly the same way.

--

--

Anton Moiseev
Angular Notes

Software developer at Farata Systems. Co-author of Angular 2 Development with TypeScript http://j.mp/ng2book