CoyoteSS

Aug 25, 2021

3 min read

Angular input validation through property decorators

Photo by Raimond Klavins on Unsplash

Often we need to validate the input parameters of our components or directives, basically the easiest way how we can do it, its just with implementing ngOnChanges hook where we can get SimpleChanges object which contains previous and current all input values, then we can work with him as we want validate, change and so on.

Approach with using property decorators

You no longer need to write a lot of duplicate logic, we can just create folder with our shared decorators for our needs that we can reuse through application, the code is as concise and understandable as possible, as well as reliable. But to understand how it works, you need firstly to know what is decorator, then you can just do these decorators according to the same type of template, changing only the logic of working with values, believe it is very easy. You don’t need to rewrite and call ngOnInit hook as described in other articles, the way we do it all is extremely simple.

First example

Imagine a situation that we need to create an input that must accept a number no more than 10.

export const Max = (limit: number): PropertyDecorator => {
return (target: object, key: string): PropertyDescriptor => {
let _value: number;

return Object.defineProperty(target, key, {
enumerable: true,
get: (): number => _value,
set: (value: number) => {
if (value > limit) {
throw new Error(`Value must be lower ${ limit }!`);
}

_value = value;
},
);
};
};
// export class AppComponent {
// @Max(10) value: number = 12;

As you can see we just make function which called “Max” and returns PropertyDecorator type, its function that must take two parameters “target” (its our component/directive class) and “key” (component/directive property name on which decorator was called), as you assumed — yes we can use them inside decorator function, in this case we need to rewrite our component property to work with his values inside our decorator function, so, we return PropertyDescriptor and pass “target” and “key” as parameters, then descriptor with getter and setter , enumerable was set to true, because its default behaviour of angular property classes.

Since we have overwritten the property descriptor, we need to somehow manually work with it, in particular, store the values somewhere and give them through the getter, this is presented in the code. We declare variable called “_value” which will be value container of our getter/setter methods. Getter just return “_value”, setter rewrite “_value” value. Inside setter we can implement any kind of logic, in this case we check that value is lower than 10 and throw error if its not.

Second example

We can cast the value to the required one instead of throwing an error. The template is the same:

export const Min = (min: number): PropertyDecorator => {
return (target: object, key: string): PropertyDescriptor => {
let _value: number;

return Object.defineProperty(target, key, {
enumerable: true,
get: (): number => _value,
set: (value: number) => {
if (value < min) {
_value = min;
return;
}

_value = value;
},
);
};
};
// export class AppComponent {
// @Min(12) value: number = -17;

This decorator checks that if passed value lower than passed decorator parameter and then fallback to that parameter, otherwise not.

Thanks for attention!