0

I want to get value of type property in class B for validate class A.

Class A is used as a property type for the property a in Class B.

class Content1 {}

class Content2 {}

class A {
  @IsValidContent()
  content: Content1 | Content2;
}

class B {
  @Type(() => A)
  @ValidateNested({ each: true })
  a: A;

  type: string;
}

export function IsValidContent(validationOptions?: ValidationOptions) {
  return (object: Object, propertyName: string) => {
    registerDecorator({
      name: "isValidContent",
      target: object.constructor,
      propertyName,
      constraints: [],
      options: validationOptions,
      validator: {
        validate(value: any, args: ValidationArguments) {

          const type = args.object["type"]; // how to get type properties from parent
          switch (type) {
            case "X":
              return isValidType(value, Content1);
            case "Y":
              return isValidType(value, Content2);
            default:
              return false;
          }
        },
      },
    });
  }
}

How to get type properties from class B in order to validate the property content in class A?

Validation decorator is IsValidContent

3
  • Is your current implementation not working? Commented May 6, 2023 at 12:12
  • @CharchitKapoor Yes, the args variable only contains properties of the child class. I cant get type property of the parent class Commented May 7, 2023 at 10:23
  • My current solution is to validate in the parent class, and then retrieve the value of the parent class to call the value of the child class Commented May 7, 2023 at 10:26

2 Answers 2

3

i have the same problem.

I have created a validator that add parent object in each child:

import { Exclude } from 'class-transformer';
import {
  Validate,
  ValidationArguments,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
} from 'class-validator';

@ValidatorConstraint({ name: 'customValidator', async: false })
export class AddParentRefConstraint implements ValidatorConstraintInterface {
  defaultMessage(): string {
    return '';
  }

  validate(
    obj: object,
    validationArguments: ValidationArguments,
  ): Promise<boolean> | boolean {
    // add the parent ref on obj
    const parentRef = new WeakRef(validationArguments.object);
    Object.defineProperty(obj, 'parentRef', {
      get: function () {
        return parentRef;
      },
    });
    Exclude()(obj, 'parentRef');
    return true;
  }
}

export function AddParentRef(validationOptions?: ValidationOptions) {
  return function (target: object, propertyKey: string | symbol) {
    return Validate(AddParentRefConstraint, validationOptions)(
      target,
      propertyKey,
    );
  };
}

A parentRef member is added in each object where the annotation is needed. Next, you can use it. I have using the @Exclude of class-transfomer on the property to ensure that the field if removed from serialisation, but if you you custom serialization, you should take care of it.

Next you can do this:

class Content1 {}

class Content2 {}

class A {
  @IsValidContent()
  content: Content1 | Content2;
}

class B {
  @AddParentRef()
  @Type(() => A)
  @ValidateNested({ each: true })
  a: A;

  type: string;
}

export function IsValidContent(validationOptions?: ValidationOptions) {
  return (object: Object, propertyName: string) => {
    registerDecorator({
      name: "isValidContent",
      target: object.constructor,
      propertyName,
      constraints: [],
      options: validationOptions,
      validator: {
        validate(value: any, args: ValidationArguments) {

          const type = args.object.parentRef["type"];
          switch (type) {
            case "X":
              return isValidType(value, Content1);
            case "Y":
              return isValidType(value, Content2);
            default:
              return false;
          }
        },
      },
    });
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Nice answer, i think u can improve this feature on class-validator github
-1

You can use the getParentObject method provided by ValidationArguments to get the parent object of the current property being validated. You can then access the type property of class B to use it in the IsValidContent decorator. here is the updated IsValidContent decorator:

export function IsValidContent(validationOptions?: ValidationOptions) {
  return (object: Object, propertyName: string) => {
    registerDecorator({
      name: "isValidContent",
      target: object.constructor,
      propertyName,
      constraints: [],
      options: validationOptions,
      validator: {
        validate(value: any, args: ValidationArguments) {
          const parentObject = args.getParentObject();
          const type = parentObject["type"];
          switch (type) {
            case "X":
              return isValidType(value, Content1);
            case "Y":
              return isValidType(value, Content2);
            default:
              return false;
          }
        },
      },
    });
  };
}

I hope this help you.

3 Comments

Property 'getParentObject' does not exist on type 'ValidationArguments'
try this: const parentObject = args.object as B; const type = parentObject.type;
args.object not included any class B properties

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.