First of all, thanks for the awesome validation solution! I use class-validator in my NestJS setup. Now I want to know if and how it is possible to check if two values match with eachother. Let's say I have a dto setup like this:
```user-create.dto.ts
export class UserCreateDto {
@IsString()
@IsNotEmpty()
firstName: string;
@IsEmail()
emailAddress: string;
@DoesMatch(o => o.emailAddress === o.emailAddressConfirm) // <---- check if email's match
@IsEmail()
emailAddressConfirm: string;
}
```
@vlapo
@vlapo how can we achieve something like this??
We do not have validator for this. Feel free open PR.
Hi guys, any update @vlapo?
Is there a way to make custom validator get access to other properties
Hi! I am posting there the solution I found to implement this control. It refers to my question/answer on StackOverflow. I am going to provide a suitable solution for this particular issue.
export class UserCreateDto {
@IsString()
@IsNotEmpty()
firstName: string;
@IsEmail()
emailAddress: string;
@Match('emailAddress')
@IsEmail()
emailAddressConfirm: string;
}
import {registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';
export function Match(property: string, validationOptions?: ValidationOptions) {
return (object: any, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [property],
validator: MatchConstraint,
});
};
}
@ValidatorConstraint({name: 'Match'})
export class MatchConstraint implements ValidatorConstraintInterface {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
return value === relatedValue;
}
}
I managed to solve a similar problem on my personal project. Hope it helps!
Added a custom message to your solution like this:
@ValidatorConstraint({name: 'Match'})
export class MatchConstraint implements ValidatorConstraintInterface {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
return value === relatedValue;
}
defaultMessage(args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
return `${relatedPropertyName} and ${args.property} don't match`;
}
}
force the property to exist on the class:
export function Match<K extends string, T extends { [$K in K]: any }>(
property: K,
validationOptions?: ValidationOptions,
) {
return (object: T, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [property],
validator: MatchConstraint,
});
};
}
@mrpharderwijk and @pieromacaluso, it's works for me. Thanks!!
Full code:
import {registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';
export function Match(property: string, validationOptions?: ValidationOptions) {
return (object: any, propertyName: string) => {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [property],
validator: MatchConstraint,
});
};
}
@ValidatorConstraint({name: 'Match'})
export class MatchConstraint implements ValidatorConstraintInterface {
validate(value: any, args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
const relatedValue = (args.object as any)[relatedPropertyName];
return value === relatedValue;
}
defaultMessage(args: ValidationArguments) {
const [relatedPropertyName] = args.constraints;
return `${relatedPropertyName} and ${args.property} don't match`;
}
}
Most helpful comment
Hi! I am posting there the solution I found to implement this control. It refers to my question/answer on StackOverflow. I am going to provide a suitable solution for this particular issue.
user-create.dto.ts
match.decorator.ts
I managed to solve a similar problem on my personal project. Hope it helps!