UNPKG

ngx-reactive-form-class-validator

Version:

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

286 lines (278 loc) 13.1 kB
import { FormArray, FormControl, Validators, FormGroup } from '@angular/forms'; import * as i0 from '@angular/core'; import { Injectable, NgModule } from '@angular/core'; import { validateSync } from 'class-validator'; import { CommonModule } from '@angular/common'; class ClassValidatorFormArray extends FormArray { constructor(controls, validatorOrOpts, asyncValidator) { super(controls, validatorOrOpts, asyncValidator); } } class ClassValidatorFormControl extends FormControl { /** * Creates a new `ClassValidatorFormControl` instance. * * @param formState Initializes the control with an initial value, * or an object that defines the initial value and disabled state. * * @param validatorOrOpts A synchronous validator function, or an array of * such functions, or an `AbstractControlOptions` object that contains validation functions * and a validation trigger. * * @param asyncValidator A single async validator or array of async validator functions * */ constructor(formState, validatorOrOpts, asyncValidator) { super(formState, validatorOrOpts, asyncValidator); this.dynamicValidator = (control) => { this.formGroupClassValue[this.name] = control.value; const validationErrors = validateSync(this.formGroupClassValue) .find(error => error.property === this.name); return validationErrors ? validationErrors.constraints : undefined; }; this.setValidatorsWithDynamicValidation(validatorOrOpts); } /** * @internal */ setNameAndFormGroupClassValue(name, value) { this.name = name; this.formGroupClassValue = value; } /** * Sets the synchronous validators that are active on this control as well as resetting the dynamic `class-validator`. Calling * this overwrites any existing sync validators. * * When you add or remove a validator at run time, you must call * `updateValueAndValidity()` for the new validation to take effect. * */ setValidatorsWithDynamicValidation(newValidator) { this.setValidators(newValidator ? [this.composeValidators(newValidator), this.dynamicValidator] : this.dynamicValidator); } composeValidators(validator) { if (validator instanceof Array) { return Validators.compose(validator); } if (validator.validators) { return this.composeValidators(validator.validators); } return validator; } } class ClassValidatorFormGroup extends FormGroup { /** * Creates a new `ClassValidatorFormGroup` instance. * * @param formClassType the `classType` containing `class-validator` decorators to be used to validate form * @param controls A collection of child controls. The key for each child is the name * under which it is registered. * * @param validatorOrOpts A synchronous validator function, or an array of * such functions, or an `AbstractControlOptions` object that contains validation functions * and a validation trigger. * * @param asyncValidator A single async validator or array of async validator functions * */ constructor(formClassType, controls, validatorOrOpts, asyncValidator) { super(controls, validatorOrOpts, asyncValidator); this.formClassType = formClassType; this.assignFormValueToClassValue(); this.setClassValidatorControlsContainerGroupClassValue(); } /** * Add a control to this group. * * This method also updates the value and validity of the control. * * @param name The control name to add to the collection * @param control Provides the control for the given name * @param options Specifies whether this FormGroup instance should emit events after a new * control is added. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` observables emit events with the latest status and value when the control is * added. When false, no events are emitted. * */ addControl(name, control, options) { super.addControl(name, control, options); this.assignFormValueToClassValue(); this.setClassValidatorControlsContainerGroupClassValue(); } /** * Remove a control from this group. * * @param name The control name to remove from the collection * @param options Specifies whether this FormGroup instance should emit events after a * control is removed. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` observables emit events with the latest status and value when the control is * removed. When false, no events are emitted. */ removeControl(name, options = {}) { super.removeControl(name, options); this.assignFormValueToClassValue(); this.setClassValidatorControlsContainerGroupClassValue(); } setClassValidatorControlsContainerGroupClassValue() { Object.entries(this.controls).forEach(([controlName, control]) => { if (control instanceof ClassValidatorFormControl) { this.controls[controlName] .setNameAndFormGroupClassValue(controlName, this.classValue); } }); } assignFormValueToClassValue() { this.classValue = Object.assign(new this.formClassType(), this.value); } } // Coming from https://github.com/angular/angular/blob/3b0b7d22109c79b4dceb4ae069c3927894cf1bd6/packages/forms/src/form_builder.ts#L14 const isAbstractControlOptions = (options) => options.asyncValidators !== undefined || options.validators !== undefined || options.updateOn !== undefined; class ClassValidatorFormBuilderService { /** * @description * Construct a new `FormGroup` instance. * * @param formClassType the `classType` containing `class-validator` decorators to be used to validate form * @param controlsConfig A collection of child controls. The key for each child is the name * under which it is registered. * * @param options Configuration options object for the `FormGroup`. The object can * have two shapes: * * 1) `AbstractControlOptions` object (preferred), which consists of: * * `validators`: A synchronous validator function, or an array of validator functions * * `asyncValidators`: A single async validator or array of async validator functions * * `updateOn`: The event upon which the control should be updated (options: 'change' | 'blur' | * submit') * * 2) Legacy configuration object, which consists of: * * `validator`: A synchronous validator function, or an array of validator functions * * `asyncValidator`: A single async validator or array of async validator functions * */ group(formClassType, controlsConfig, options) { // Coming from https://github.com/angular/angular/blob/3b0b7d22109c79b4dceb4ae069c3927894cf1bd6/packages/forms/src/form_builder.ts#L59 const controls = this.reduceControls(controlsConfig); let validators = null; let asyncValidators = null; let updateOn; if (options) { if (isAbstractControlOptions(options)) { // `options` are `AbstractControlOptions` validators = options.validators ? options.validators : null; asyncValidators = options.asyncValidators ? options.asyncValidators : null; updateOn = options.updateOn ? options.updateOn : undefined; } else { // `options` are legacy form group options validators = options['validator'] !== null ? options['validator'] : null; asyncValidators = options['asyncValidator'] !== null ? options['asyncValidator'] : null; } } return new ClassValidatorFormGroup(formClassType, controls, { asyncValidators, updateOn, validators }); } /** * Constructs a new `FormArray` from the given array of configurations, * validators and options. * * @param controlsConfig An array of child controls or control configs. Each * child control is given an index when it is registered. * * @param validatorOrOpts A synchronous validator function, or an array of * such functions, or an `AbstractControlOptions` object that contains * validation functions and a validation trigger. * * @param asyncValidator A single async validator or array of async validator * functions. */ array(controlsConfig, validatorOrOpts, asyncValidator) { const controls = controlsConfig.map(control => this.createControl(control)); return new ClassValidatorFormArray(controls, validatorOrOpts, asyncValidator); } /** * @description * Construct a new `FormControl` with the given state, validators and options. * * @param formState Initializes the control with an initial state value, or * with an object that contains both a value and a disabled status. * * @param validatorOrOpts A synchronous validator function, or an array of * such functions, or an `AbstractControlOptions` object that contains * validation functions and a validation trigger. * * @param asyncValidator A single async validator or array of async validator * functions. * * @usageNotes * * ### Initialize a control as disabled * * The following example returns a control with an initial value in a disabled state. * * <code-example path="forms/ts/formBuilder/form_builder_example.ts" region="disabled-control"> * </code-example> */ control(formState, validatorOrOpts, asyncValidator) { return new ClassValidatorFormControl(formState, validatorOrOpts, asyncValidator); } // Coming from https://github.com/angular/angular/blob/3b0b7d22109c79b4dceb4ae069c3927894cf1bd6/packages/forms/src/form_builder.ts#L133 reduceControls(controlsConfig) { const controls = {}; Object.keys(controlsConfig).forEach(controlName => { controls[controlName] = this.createControl(controlsConfig[controlName]); }); return controls; } createControl(controlConfig) { if (controlConfig instanceof FormControl || controlConfig instanceof FormGroup || controlConfig instanceof FormArray) { return controlConfig; } else if (Array.isArray(controlConfig)) { const value = controlConfig[0]; const validator = controlConfig.length > 1 ? controlConfig[1] : null; const asyncValidator = controlConfig.length > 2 ? controlConfig[2] : null; return this.control(value, validator, asyncValidator); } else { return this.control(controlConfig); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderService, decorators: [{ type: Injectable }] }); class ClassValidatorFormBuilderModule { static forRoot() { return { ngModule: ClassValidatorFormBuilderModule, providers: [ ClassValidatorFormBuilderService, ], }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderModule, imports: [CommonModule] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderModule, providers: [ClassValidatorFormBuilderService], imports: [CommonModule] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ClassValidatorFormBuilderModule, decorators: [{ type: NgModule, args: [{ imports: [CommonModule], providers: [ClassValidatorFormBuilderService], }] }] }); /** * Generated bundle index. Do not edit. */ export { ClassValidatorFormArray, ClassValidatorFormBuilderModule, ClassValidatorFormBuilderService, ClassValidatorFormControl, ClassValidatorFormGroup }; //# sourceMappingURL=ngx-reactive-form-class-validator.mjs.map