Skip to content

Commit

Permalink
feat: update for correct work new version of class-validator
Browse files Browse the repository at this point in the history
  • Loading branch information
EndyKaufman committed May 4, 2020
1 parent 445b3bc commit f7da8dd
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
## Installation

```bash
npm i --save ngx-dynamic-form-builder
npm i --save class-transformer class-validator ngx-dynamic-form-builder
```

## Links
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
[placeholder]="strings.regionNum">
<mat-error *ngIf="errors?.regionNum?.length">{{errors?.regionNum[0]}}</mat-error>
<mat-error *ngIf="nativeErrors?.regionNum?.required">
name should not be empty (native angular)
region num should not be empty (native angular)
</mat-error>
</mat-form-field>
<div class="full-width">
Expand Down
2 changes: 1 addition & 1 deletion libs/ngx-dynamic-form-builder/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
## Installation

```bash
npm i --save ngx-dynamic-form-builder
npm i --save class-transformer class-validator ngx-dynamic-form-builder
```

## Links
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ValidationMetadata } from 'class-validator/metadata/ValidationMetadata';
import { ValidationMetadata } from 'class-validator/types/metadata/ValidationMetadata';
import { DynamicFormGroup } from '../utils/dynamic-form-group';
import { ValidatorFunctionType } from './validator-function-type';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AsyncValidatorFn, FormControl, ValidatorFn } from '@angular/forms';
import { ValidationMetadata } from 'class-validator/metadata/ValidationMetadata';
import { ValidationMetadata } from 'class-validator/types/metadata/ValidationMetadata';
import { Observable } from 'rxjs';
import { DynamicFormGroupField } from '../models/dynamic-form-group-field';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function transformValidationErrors(errors: ValidationError[]): ShortValid
customErrors[error.property] = [];
}

if ((customErrors[error.property] as string[]).indexOf(error.constraints[key]) === -1) {
if (error.constraints && (customErrors[error.property] as string[]).indexOf(error.constraints[key]) === -1) {
(customErrors[error.property] as string[]).push(error.constraints[key]);
}
});
Expand Down
70 changes: 37 additions & 33 deletions libs/ngx-dynamic-form-builder/src/lib/utils/dynamic-form-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import {
import { classToClass, plainToClass } from 'class-transformer';
import { ClassType } from 'class-transformer/ClassTransformer';
import {
getFromContainer,
MetadataStorage,
getMetadataStorage,
validate,
ValidationTypes,
Validator,
ValidatorOptions,
validateSync,
} from 'class-validator';
import { ValidationMetadata } from 'class-validator/metadata/ValidationMetadata';
import { ValidationMetadata } from 'class-validator/types/metadata/ValidationMetadata';
import 'reflect-metadata';
import { BehaviorSubject, from, Observable, of, Subject, Subscription } from 'rxjs';
import { flatMap, map, mapTo, delay, tap } from 'rxjs/operators';
import { BehaviorSubject, from, merge, of, Subject, Subscription } from 'rxjs';
import { flatMap, map, mapTo, tap } from 'rxjs/operators';
import { Dictionary } from '../models/dictionary';
import { DynamicFormGroupField } from '../models/dynamic-form-group-field';
import { ErrorPropertyName } from '../models/error-property-name';
Expand Down Expand Up @@ -131,7 +131,7 @@ export class DynamicFormGroup<TModel> extends FormGroup {
validatorOptions = cloneDeep(this._validatorOptions);
}

return from(validate(this.object, validatorOptions))
return of(validateSync(this.object, validatorOptions))
.pipe(
map((errors) => {
if (!externalErrors) {
Expand Down Expand Up @@ -450,7 +450,7 @@ export class DynamicFormGroup<TModel> extends FormGroup {
*
* @param object the data to assign to all controls of the form group and sub groups
*/
private setObject(object: TModel) {
private setObject(object: TModel, fromPending = false) {
if (object instanceof this.factoryModel) {
this._object = this.classToClass(object); // Ensure correct type
} else {
Expand Down Expand Up @@ -509,7 +509,7 @@ export class DynamicFormGroup<TModel> extends FormGroup {
} else {
// Create control
const controlValue = this._object && objectArray && objectArray[i] ? objectArray[i] : undefined;
const newFormControl = new FormControl(controlValue, formControl.validator);
const newFormControl = new FormControl(controlValue, formControl ? formControl.validator : undefined);
newFormControl.setParent(this);

// Add the control to the FormArray
Expand All @@ -534,18 +534,17 @@ export function getClassValidators<TModel>(
validatorOptions?: ValidatorOptions
) {
// Get the validation rules from the object decorators
const allValidationMetadatas: ValidationMetadata[] = getFromContainer(MetadataStorage).getTargetValidationMetadatas(
const allValidationMetadatas: ValidationMetadata[] = getMetadataStorage().getTargetValidationMetadatas(
factoryModel,
''
);

// Get the validation rules for the validation group: https://github.com/typestack/class-validator#validation-groups
const validationGroupMetadatas: ValidationMetadata[] = getFromContainer(MetadataStorage).getTargetValidationMetadatas(
const validationGroupMetadatas: ValidationMetadata[] = getMetadataStorage().getTargetValidationMetadatas(
factoryModel,
'',
validatorOptions && validatorOptions.groups ? validatorOptions.groups : undefined
);

const formGroupFields = {};
const validator = new Validator();

Expand Down Expand Up @@ -597,7 +596,9 @@ export function getClassValidators<TModel>(
) {
fieldDefinition.data
.filter((validationFunction, index) => index > 0 && typeof validationFunction === 'function')
.forEach((validationFunction) => fieldDefinition.validationFunctions.push(validationFunction));
.forEach((validationFunction) =>
fieldDefinition.validationFunctions.push({ type: 'sync', validator: validationFunction })
);
fieldDefinition.data = fieldDefinition.data[0];
}

Expand Down Expand Up @@ -668,8 +669,8 @@ export function getClassValidators<TModel>(
objectToValidate !== undefined ? objectToValidate : control.value,
validatorOptions
).pipe(
map((errors) => errors.length === 0),
map((validateState) => getIsValidResult(validateState, validationMetadata, 'nestedValidate'))
map((errors: ShortValidationErrors) => Object.keys(errors).length === 0),
map((validateState: boolean) => getIsValidResult(validateState, validationMetadata, 'nestedValidate'))
);
},
};
Expand All @@ -686,20 +687,9 @@ export function getClassValidators<TModel>(
if (!control) {
return of(null);
}

const isValid =
control.parent && control.parent.value
? validator.validateValueByMetadata(control.value, validationMetadata)
: true;
let validateState$ = of(isValid);
if (!isValid && conditionalValidations.length > 0) {
validateState$ = setObjectValueAndGetValidationErrors(fieldName, control, validatorOptions).pipe(
map((validateErrors) => (validateErrors && validateErrors[fieldName] ? false : true))
);
}

return validateState$.pipe(
map((validateState) => getIsValidResult(validateState, validationMetadata, 'dynamicValidate'))
return setObjectValueAndGetValidationErrors(fieldName, control, validatorOptions).pipe(
map((errors: ShortValidationErrors) => getAllErrors(errors, fieldName).length === 0),
map((validateState: boolean) => getIsValidResult(validateState, validationMetadata, 'dynamicValidate'))
);
},
};
Expand All @@ -710,8 +700,8 @@ export function getClassValidators<TModel>(
type: 'async',
validator: function (control: FormControl) {
return setObjectValueAndGetValidationErrors(fieldName, control, validatorOptions).pipe(
map((errors) => getAllErrors(errors, fieldName).length === 0),
map((validateState) => getIsValidResult(validateState, validationMetadata, 'customValidation'))
map((validateErrors: ShortValidationErrors) => (validateErrors && validateErrors[fieldName] ? false : true)),
map((validateState: boolean) => getIsValidResult(validateState, validationMetadata, 'customValidation'))
);
},
};
Expand Down Expand Up @@ -832,7 +822,7 @@ function getValidateErrors(
control: FormControl,
dataToValidate: any,
validatorOptions?: ValidatorOptions
) {
): ShortValidationErrors {
/* todo: future feature - get errors from parent, without run validation again, now it is not work
return (control?.root?.valueChanges || control?.parent?.valueChanges || control?.valueChanges || of({})).pipe(
flatMap(() => (control.parent && control.parent.value ? from(validate(dataToValidate, validatorOptions)) : of([]))),
Expand All @@ -845,9 +835,23 @@ function getValidateErrors(
? control.parent.customValidateErrors
: of({})
)
// or
if (false && control.parent && control.parent.value && control.parent instanceof DynamicFormGroup) {
return merge(of({}), control.root.valueChanges, control.parent.valueChanges, control.valueChanges).pipe(
map(
() =>
control.parent instanceof DynamicFormGroup && {
[fieldName]: control.parent.customValidateErrors.value[fieldName],
}
)
);
}
);*/
return (parent && parent.value ? from(validate(dataToValidate, validatorOptions)) : of([])).pipe(
map((errors) => transformValidationErrors(errors))
return (parent && parent.value ? of(validateSync(dataToValidate, validatorOptions)) : of([])).pipe(
map((errors) => {
const customErrors = transformValidationErrors(errors);
return customErrors;
})
);
}

Expand Down

0 comments on commit f7da8dd

Please sign in to comment.