A lightweight library for dynamically validate Angular reactive forms using class-validator library.
npm install ngx-reactive-form-class-validatorsetValidators/setValidatorsWithDynamicValidation methods npm install --save ngx-reactive-form-class-validator
// OR
yarn add ngx-reactive-form-class-validator
###### _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._
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;
}
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
#### Eager Validation Option
By default, ngx-reactive-form-class-validator validates form controls after the form is fully initialized (ngAfterViewInit).
If you want validation to run immediately after form initialization (for example, in ngAfterViewInit or just after you create a FormGroup), you can enable eager validation at the ClassValidatorFormGroup/FormBuilder level.
``
import { ClassValidatorFormGroup, ClassValidatorFormControl } from 'ngx-reactive-form-class-validator';
const formGroup = new ClassValidatorFormGroup({
email: new ClassValidatorFormControl(''),
password: new ClassValidatorFormControl('')
}, null, { eagerValidation: true }); // 👈 Enable eager validation here
// Or using the form builder
public constructor(
private fb: ClassValidatorFormBuilderService,
) { }
profileForm = this.fb.group(
Profile,
{
firstName: [''],
lastName: [''],
email: [''],
address: this.fb.group(Address,
{
street: [''],
city: [''],
state: [''],
zip: ['']
}
),
},
undefined,
{ eagerValidation: true } // 👈 Enable eager validation here
);
`
this.fb.group (Profile, {
email: ['', Validators.required],
...
}
)
// OR
new ClassValidatorFormGroup(Profile, {
email: new ClassValidatorFormControl('', Validators.required)
})
#### Providing validators using setValidators/setValidatorsWithDynamicValidation methodssetValidators
Both 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
or normally (We don't recommend importing it normally because that will create multiple instances of ClassValidatorFormBuilderService).app.module.ts
imports: [
...
ClassValidatorFormBuilderModule.forRoot(),
...
],
$3
An Angular injectable service having the same methods as Angular FormBuilder except a minor change of group method signature, see below: group(
classType: ClassType, // 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.
$3
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,
// Angular FormGroup constructor parameters
controls: {
[key: string]: AbstractControl;
},
validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null,
asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null,
) {
...
}
$3
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.