Skip to content

abarghoud/ngx-reactive-form-class-validator

Repository files navigation

ngx-reactive-form-class-validator

A lightweight library for dynamically validate Angular reactive forms using class-validator library.

npm version   npm minified size   Code coverage   Build status  

Table of contents

Installation

npm install --save ngx-reactive-form-class-validator

// OR

yarn add ngx-reactive-form-class-validator

Peer dependencies

"@angular/common": ">= 2.0.0 <= ^18.0.0",
"@angular/core": ">= 2.0.0 <= ^18.0.0",
"@angular/forms": ">= 2.0.0 <= ^18.0.0",
"class-validator": ">= 0.12.0 <= ^0.14.0"
While this library will function with any version of class-validator within this range, we strongly recommend using class-validator ^0.14.0 or later due to a critical security vulnerability addressed in versions 0.14.0 and beyond. This ensures the highest level of security for your application.

Usage

Defining classes with validators and deserializers

Please note that properties without a class-validator decorator will not be validated, see class-validator profile.ts

import { IsEmail, IsNotEmpty, ValidateNested } from 'class-validator';  
  
class Profile {  
  @IsNotEmpty()  
  public firstName: string;  
  
  @IsNotEmpty()  
  public lastName: string;  

  @IsEmail()  
  public email: string;  	
  
  @ValidateNested()  
  public address: Address;  
}

address.ts

import { IsNotEmpty, IsOptional, ValidateNested } from 'class-validator';  

class Address {  
  @IsNotEmpty()  
  public street: string;  
  
  @IsNotEmpty()  
  public city: string;  
  
  @IsOptional()  
  public state: string;  
  
  @IsNotEmpty()  
  public zip: string;  
} 

Untyped classes

Untyped version of ngx-class-validator form classes exist in order to be backward compatible with angular untyped form classes

Creating a ClassValidatorFormGroup

Using ClassValidatorFormBuilderService

As described here to be able to use the ClassValidatorFormBuilderService, you need to import ClassValidatorFormBuilderModule.

app.module.ts

imports: [  
  ...
  ClassValidatorFormBuilderModule.forRoot(),  
  ...
],

Then in your component profile-form.component.ts

public constructor(  
 private fb: ClassValidatorFormBuilderService,  
) { }

 profileForm =  this.fb.group(Profile,
    {
     firstName:  [''],
     lastName:  [''],
     email: [''],
     address: this.fb.group(Address,
	      {
		      street:  [''],
		      city:  [''],
		      state:  [''],
		      zip:  ['']
		  }
	  ),
    });

Using ClassValidatorFormGroup class

As it's possible with angular FormGroup class we can directly create a ClassValidatorFormGroup using the constructor

export class ProfileFormComponent {
  profileForm = new ClassValidatorFormGroup({
    firstName: new ClassValidatorFormControl(''),
    lastName: new ClassValidatorFormControl(''),
  });
}

Now, setting value to any of form controls, will perfom the validator set in the corresponding class.

this.profileForm.controls.email.setValue('notEmailValue');
console.log(this.profileForm.controls.email) // { isEmail: 'email must be an email' }

this.profileForm.controls.email.setValue('email@email.com');
console.log(this.profileForm.controls.email) // null

Add custom validators

It is possible as well to combine dynamic validation with custom validation. There are several ways to do it:

Providing validators when creating the ClassValidatorFormControl

this.fb.group (Profile, {  
      email: ['', Validators.required],
      ...
  }
)

// OR

new ClassValidatorFormGroup(Profile, {
	email: new ClassValidatorFormControl('', Validators.required)
})

Providing validators using setValidators/setValidatorsWithDynamicValidation methods

Both setValidators and setValidatorsWithDynamicValidation replace validators provided in parameter, the only one difference is that setValidatorsWithDynamicValidation add given validators as well as re-enable dynamic validation, as the setValidators method replace validators with given ones without re-enabling dynamic validation.

emailControl.setValidators(Validators.required); // there will be only Validators.required validator

emailControl.setValidatorsWithDynamicValidation(Validators.required) // there will be Validaros.required validator as well as dynamic validator

Available classes

ClassValidatorFormBuilderModule

An Angular module that provides ClassValidatorFormBuilderService for dependency injection. It can either be imported forRoot or normally (We don't recommend importing it normally because that will create multiple instances of ClassValidatorFormBuilderService).

app.module.ts

imports: [  
  ...
  ClassValidatorFormBuilderModule.forRoot(),  
  ...
],

ClassValidatorFormBuilderService

An Angular injectable service having the same methods as Angular FormBuilder except a minor change of group method signature, see below:

group(  
  classType: ClassType<any>, // The class type of the form group value.
  // Angular FormBuilder group method parameters
  controlsConfig: { [p: string]: any },  
  options?: AbstractControlOptions | { [p: string]: any } | null,  
): ClassValidatorFormGroup;

classType parameter

We've introduced a new parameter called classType (a class type containing class-validator decorators) that you should provide, to enable us to perform dynamic validations.

ClassValidatorFormGroup

A typescript class extending angular FormGroup class, with a minor change of constructor signature, the classType parameter.

export class ClassValidatorFormGroup extends FormGroup {        
 public constructor(  
      private readonly classType: ClassType<any>, 
      // Angular FormGroup constructor parameters
      controls: {  
          [key: string]: AbstractControl;  
      },  
      validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,  
      asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null,  
  ) {  
    ... 
  }

ClassValidatorFormControl

A typescript class extending angular FormControl class, that will use the classType instance to perform validations and assign validation errors to the ClassValidatorFormControl.

As it extends angular FormControl class, it contains all FormControl methods, with a custom new method:

setValidatorsWithDynamicValidation(newValidator: ValidatorFn | ValidatorFn[] | AbstractControlOptions | undefined): void

This method has the same signature as FormControl setValidators method. In addition it re-enables dynamic validation when disabled.

Developer note

We are open for proposals, so please don't hesitate to create issues if you want to report any bugs/proposals/feature requests.