How to validate 2d arrays?
Hello,
I have something like this
@Type is from class-transformer. I tried to search for the issues but I could not find anything.
export class Child {
@IsDefined()
@IsString()
@IsNotEmpty()
name: string;
}
export class Parent {
@IsArray()
@IsNotEmpty()
@Type((type) => Child)
@ValidateNested()
children: Child[][];
}
const parent = new Parent();
let res;
// I need `as any` because I'm using strictNullChecks
parent.children= 123 as any;
res = validateSync(parent); // this fails
parent.children= [] as any;
res = validateSync(parent); // this passes
parent.children= [[]] as any;
res = validateSync(parent); // this passes
parent.children= [[ { name: null } ]] as any;
res = validateSync(parent); // this passes
Even if the type Child is changed to JS native types like number or string. How can I validate something like this?
Currently we do not have support for multidimensional arrays. You have to create your own custom validator.
Currently we do not have support for multidimensional arrays. You have to create your own custom validator.
Not really sure how that would work, can you point us in the right direction here?
Here's my take on this, @MarkMurphy and @drewwiens
import { IsString, Validate, validate } from 'class-validator';
export class Student {
@IsString()
name: string;
}
/** Validates an array of students */
async function validateStudentArray(input: Student[]): Promise<boolean> {
const validityArray = await Promise.all(
input.map(async student => {
const errors = await validate(student); // you could also use validate('Student', student);
if (errors.length === 0) {
return true;
} else {
return false;
}
}),
);
const result = validityArray.reduce<boolean>(
(isValid, currentValue) => isValid && currentValue,
true,
);
return result;
}
export class School {
@Validate(validateStudentArray, { each: true })
nestedStudents: Student[][];
}
I'm sure some generalization could be done here
By following the doc, the correct custom validation class should implement ValidatorConstraintInterface.
Here is an example, I had to validate a 2D GPS coordinates.
import {
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';
function between(value: number, min: number, max: number) {
return min <= value && value <= max;
}
@ValidatorConstraint({ name: 'IsLatitudeLongitude', async: false })
export class IsLatitudeLongitude implements ValidatorConstraintInterface {
errors: string[] = [];
async validate(values: number[]) {
this.errors = [];
const long = values[0];
const lat = values[1];
if (values.length !== 2)
this.errors.push(
`coordinates ${values} should contain a longitude and a latitude`,
);
if (typeof long !== 'number')
this.errors.push(`longitude ${long} should be a number`);
if (typeof lat !== 'number')
this.errors.push(`latitude ${lat} should be a number`);
if (!between(long, -180, 180))
this.errors.push(`longitude ${long} is out of range`);
if (!between(lat, -90, 90))
this.errors.push(`latitude ${lat} is out of range`);
return this.errors.length === 0;
}
defaultMessage() {
return this.errors.join('; ');
}
}
Then you can use it to validate a single Point @Validate(IsLatitudeLongitude) or an array @Validate(IsLatitudeLongitude, { each: true })
As mentioned by others, you can use a custom validator for this.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.