class-validator
class-validator copied to clipboard
fix: @ValidateIf receives transformed nested object instead of POJO
I have the following class definitions:
class Field {
@IsString()
readonly name: string;
@IsString()
@IsIn(['values', 'numbers', 'dates'])
readonly type: string;
@ValidateNested()
@Type(() => Rule)
@IsNotEmpty()
readonly rules: Rule[];
}
class Rule {
@ValidateIf((a, b) => { console.log(b); return true; })
@IsDate()
readonly fromDate: Date;
@IsDate()
readonly toDate: Date;
@IsNumber()
readonly fromNumber: number;
@IsNumber()
readonly toNumber: number;
@IsString()
readonly label: string;
@IsNumber()
readonly value: number;
@IsNumber()
readonly rate: number;
}
Validating properties of class Rule
directly depends on value of property type
of Field
class object but in callback of ValidateIf
decorator I've got object of Rule
class. So it makes impossible to achieve conditional validation on nested objects.
Anyone on this?
+1 Anyone on this?
@NoNameProvided I'm considering to submit a PR for this issue, is that okay? I'd need some guidance tho. I've explored the internals and an outlined solution can be:
- Add
context
to the signature of theValidateIf
decorator (decorators.ts
).
export function ValidateIf(condition: (object: any, value: any, context: any) => boolean, validationOptions?: ValidationOptions)
- Pass the context to the validator in the
conditionalValidations()
(ValidationExecutor.ts
):
.map(metadata => metadata.constraints[0](object, value, metadata.context))
In the use-case given by @tsamsiyu, the ValidateIf decorator should be used like the following, in case we want to validate fromDate
ONLY IF the property name
in the Field class is provided:
class Rule {
@ValidateIf((obj, value, context) => { !!return context.Field.name })
@IsDate()
readonly fromDate: Date;
}
Does it look the right way to approach this problem?
After digging a bit more in the internals, I realized that the approach I mentioned above would not work.
@NoNameProvided I submitted a PR https://github.com/typestack/class-validator/pull/301 with tests included. I'd appreciate if you can check it out and give your feedback. Btw, congrats for the project, I'm a big fan of it.
@ChrisGatzo and @tsamsiyu I hope this solves the problem.
You can use groups in this case:
class Field {
@IsString({ always: true })
name: string;
@IsString({ always: true })
@IsIn(['values', 'numbers', 'dates'])
type: 'values' | 'numbers' | 'dates';
@ValidateNested({ always: true })
@Type(() => Rule)
@IsNotEmpty({ always: true })
rules: Rule[];
}
class Rule {
@IsDate({ groups: ['dates']})
fromDate: Date;
@IsNumber({}, { groups: ['numbers']})
someNumber: number;
}
const t = new Field();
t.name = 'supertest';
t.type = 'numbers';
t.rules = [new Rule()];
console.log(validateSync(t, {groups: [t.type]})); // only someNumber field error is provided
https://stackblitz.com/edit/class-validator-gh278?file=index.ts
@vlapo I created a PR for this since I frequently run into it validating config files I get from customers. Please let me know if you see any issues or any better ways for me to accomplish my goal of supporting shorthand syntax as well as nested configs (ideally without transforming first since I want to be able to give very specific errors to users).
The first comment mentions the decorator receives a transformed nested class instead of a plain object. If that is the case, then it's a bug and should be fixed.
Note: It seems there is a test for passing in a class instance, so this was intended, however, it doesn't make sense as on an invalid object the validation will fail on the nested object before the ValidateIf
decorator is reached.
You can use groups in this case:
https://stackblitz.com/edit/class-validator-gh278?file=index.ts
This doesn't really work in the case of using with Nestjs ValidationPipe
. Would appreciate if we can pass context to nested objects instead.
Anyone knows how to make it work with global ValidationPipe of NestJs?
Anyone knows how to make it work with global ValidationPipe of NestJs?
https://stackblitz.com/edit/class-validator-gh278-9bsxzm?file=index.ts
2 years passed and there is no solution for this, we have to create a new feature in the form of context
Anyone knows how to make it work with global ValidationPipe of NestJs?
https://stackblitz.com/edit/class-validator-gh278-9bsxzm?file=index.ts
not working, groups has no effect