class-validator icon indicating copy to clipboard operation
class-validator copied to clipboard

feat: IsOptional allow empty strings

Open renehauck opened this issue 5 years ago • 11 comments

I would like to extend the decorator "IsOptional" for my validation. I would like empty strings like "" to be valid as well. I started with this, but this seems to be the wrong approach:

export function IsOptionalWithEmptyString(validationOptions?: ValidationOptions) {
    return function (object: Object, propertyName: string) {
        registerDecorator({            
            name: "isOptionalWithEmptyString",
            target: object.constructor,
            propertyName: propertyName,
            constraints: [function (object, value) {
                return object[propertyName] !== null && object[propertyName] !== undefined && object[propertyName] !== "";
            }],
            options: validationOptions,
            validator: ?
        });
    };
}

How could I implement this? Thank you for your work.

renehauck avatar Mar 07 '19 11:03 renehauck

Duplicate of #232?

opyate avatar Mar 08 '19 09:03 opyate

Thanks for your answer :smiley: , but I don't think this is a duplicate, because #232 is more about a discussion about whether "IsOptional" should also allow empty strings. I think it's ok that "IsOptional" doesn't implement empty strings, but I'd like to implement "IsOptionalWithEmptyString". Or more generally, how can I develop a decorator that disables the following decorators due to a condition?

renehauck avatar Mar 08 '19 11:03 renehauck

Any update ?

None of the code bellow is working, I need to allow an empty string or an url:

  @IsDefined()
  @ValidateIf(e => e !== '') // expected to allow empty string by skipping @IsUrl
  @IsUrl()
  readonly externalLink: string = '';

  @IsDefined()
  @ValidateIf(e => e === '') // allow everything ?
  @IsUrl()
  readonly externalLink: string = '';

https://github.com/typestack/class-validator#conditional-validation

externalLink === '' should be valid externalLink === null should be invalid externalLink === undefined should be invalid externalLink === 'https://github.com/typestack/class-validator/issues/326' should be valid

ambroiseRabier avatar Apr 25 '19 21:04 ambroiseRabier

I have found a solution for this, you can create a new decorator wrapping ValidateIf like as follows.

import { ValidationOptions, ValidateIf } from 'class-validator';

export function IsOptional(validationOptions?: ValidationOptions) {
  return ValidateIf((obj, value) => {
    return value !== null && value !== undefined && value !== '';
  }, validationOptions);
}

pepsighan avatar Jul 15 '19 11:07 pepsighan

@ambroiseRabier try this out

  @IsUrl()
  @ValidateIf(e => e.externalLink !== '') // check only when blank string not found
  readonly externalLink: string = '';

Because in @ValidateIf first parameter is an object containing the all property of current class not the property it self.

daxaymakwana avatar Aug 03 '19 06:08 daxaymakwana

@NoNameProvided Can we add option to IsOptional to allow empty string?

For example, To allow empty string to pass.

@IsString()
@IsOptional(null, { allowEmptyString: false })
name: string;

What do you think?

daxaymakwana avatar Feb 17 '21 07:02 daxaymakwana

For those who are looking for a clean approach, you could use the combination of @IsOptional with @IsNotEmpty():

@IsNotEmpty()
@IsString()
@IsOptional()
name: string;

As the decorators are applied in the reverse order @A @B target => @A(@B(target)), first, we check if there is some value, then if it is a string, and then that the string is not empty.

vladi-strilets avatar Sep 21 '21 07:09 vladi-strilets

Here's my workaround for optional strings:

export class Customer {

  ...

  @ValidateIf((customer) => customer.displayName !== '')
  @IsString()
  @IsOptional()
  displayName?: string;

  ...
}

This validation accepts empty strings ''.

braaar avatar Jan 24 '22 14:01 braaar

In case someone is searching for a way to remove properties with empty strings. You could combine IsOptional with Transform from class-transformer:

@IsUrl()
@IsOptional()
@Transform((params) => (params.value?.length > 0 ? params.value : undefined))
displayName?: string;

elovin avatar Sep 16 '22 16:09 elovin

I ended up adding the @Transform following @elovin 's suggestion. Works like a charm but it doesn't look clean :(

@Transform((field) => (!field.value || /^\s*$/.test(field.value)? undefined: field.value))

robertorosas avatar Sep 20 '22 19:09 robertorosas

In our Nest app we just have our own implementation of the IsOptional decorator:

import { ValidateIf, ValidationOptions } from 'class-validator'

export function IsOptional(validationOptions?: ValidationOptions) {
  return ValidateIf((obj, value) => {
    return value !== null && value !== undefined && value !== ''
  }, validationOptions)
}

But you have to watch out when autocompleting it during use, so that it imports the custom one and not the default IsOptional.

martinsotirov avatar Sep 21 '22 07:09 martinsotirov