Skip to content

Commit fb8485d

Browse files
authored
fix(core): update form validity when changing built-in validations (#1887)
fix #1493
1 parent 73f0316 commit fb8485d

File tree

4 files changed

+33
-17
lines changed

4 files changed

+33
-17
lines changed

src/core/src/lib/extensions/field-expression/field-expression.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FormlyFieldConfig, FormlyValueChangeEvent, FormlyFieldConfigCache } from '../../components/formly.field.config';
2-
import { isObject, isNullOrUndefined, isFunction, FORMLY_VALIDATORS, defineHiddenProp } from '../../utils';
2+
import { isObject, isNullOrUndefined, isFunction, defineHiddenProp } from '../../utils';
33
import { evalExpression, evalStringExpression, evalExpressionValueSetter } from './utils';
44
import { Observable } from 'rxjs';
55
import { FormlyExtension } from '../../services/formly.config';
@@ -136,7 +136,6 @@ export class FieldExpressionExtension implements FormlyExtension {
136136

137137
let markForCheck = false;
138138
const expressionProperties = field._expressionProperties;
139-
const validators = FORMLY_VALIDATORS.map(v => `templateOptions.${v}`);
140139

141140
for (const key in expressionProperties) {
142141
let expressionValue = evalExpression(expressionProperties[key].expression, { field }, [field.model, field.options.formState, field]);
@@ -170,10 +169,6 @@ export class FieldExpressionExtension implements FormlyExtension {
170169
control.patchValue(expressionValue);
171170
}
172171
}
173-
174-
if (validators.indexOf(key) !== -1 && field.formControl) {
175-
field.formControl.updateValueAndValidity({ emitEvent: false });
176-
}
177172
}
178173
}
179174

src/core/src/lib/extensions/field-form/field-form.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export class FieldFormExtension implements FormlyExtension {
2727
}
2828

2929
const updateValidity = this.setValidators(field);
30-
updateValidity && (field.formControl as any)._updateTreeValidity();
30+
updateValidity && (field.formControl as any)._updateTreeValidity({ emitEvent: false });
3131
}
3232

3333
private addFormControl(field: FormlyFieldConfigCache) {

src/core/src/lib/extensions/field-validation/field-validation.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FormlyExtension, FieldValidatorFn, FormlyConfig } from '../../services/formly.config';
22
import { FormlyFieldConfigCache } from '../../components/formly.field.config';
33
import { AbstractControl, Validators, ValidatorFn } from '@angular/forms';
4-
import { isObject, FORMLY_VALIDATORS, defineHiddenProp, isUndefined, isPromise } from '../../utils';
4+
import { isObject, FORMLY_VALIDATORS, defineHiddenProp, isUndefined, isPromise, wrapProperty } from '../../utils';
55

66
/** @experimental */
77
export class FieldValidationExtension implements FormlyExtension {
@@ -29,7 +29,7 @@ export class FieldValidationExtension implements FormlyExtension {
2929
return;
3030
}
3131

32-
const validators: ValidatorFn[] = type === 'validators' ? this.getPredefinedFieldValidation(field) : [];
32+
const validators: ValidatorFn[] = type === 'validators' ? [this.getPredefinedFieldValidation(field)] : [];
3333
if (field[type]) {
3434
for (const validatorName in field[type]) {
3535
if (validatorName === 'validation' && !Array.isArray(field[type].validation)) {
@@ -51,14 +51,25 @@ export class FieldValidationExtension implements FormlyExtension {
5151
);
5252
}
5353

54-
private getPredefinedFieldValidation(field: FormlyFieldConfigCache): ValidatorFn[] {
55-
return FORMLY_VALIDATORS
56-
.filter(opt => (field.templateOptions && field.templateOptions.hasOwnProperty(opt)) || (field.expressionProperties && field.expressionProperties[`templateOptions.${opt}`]))
57-
.map((opt) => (control: AbstractControl) => {
54+
private getPredefinedFieldValidation(field: FormlyFieldConfigCache): ValidatorFn {
55+
let VALIDATORS = [];
56+
FORMLY_VALIDATORS.forEach(opt => wrapProperty(field.templateOptions, opt, (value, oldValue) => {
57+
VALIDATORS = VALIDATORS.filter(o => o !== opt);
58+
if (value != null && value !== false) {
59+
VALIDATORS.push(opt);
60+
}
61+
if (value !== oldValue && field.formControl) {
62+
field.formControl.updateValueAndValidity({ emitEvent: false });
63+
}
64+
}));
65+
66+
return (control: AbstractControl) => {
67+
if (VALIDATORS.length === 0) {
68+
return null;
69+
}
70+
71+
return Validators.compose(VALIDATORS.map(opt => () => {
5872
const value = field.templateOptions[opt];
59-
if (value === false) {
60-
return null;
61-
}
6273
switch (opt) {
6374
case 'required':
6475
return Validators.required(control);
@@ -73,7 +84,8 @@ export class FieldValidationExtension implements FormlyExtension {
7384
case 'max':
7485
return Validators.max(value)(control);
7586
}
76-
});
87+
}))(control);
88+
};
7789
}
7890

7991
private wrapNgValidatorFn(field: FormlyFieldConfigCache, validator: string | FieldValidatorFn, validatorName?: string) {

src/core/src/lib/services/formly.form.builder.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,15 @@ describe('FormlyFormBuilder service', () => {
669669
});
670670
});
671671
});
672+
673+
it(`should take account of built-in validator changes`, () => {
674+
field.templateOptions = {};
675+
builder.buildForm(form, [field], {}, {});
676+
expect(field.formControl.valid).toBeTruthy();
677+
678+
field.templateOptions.required = true;
679+
expect(field.formControl.valid).toBeFalsy();
680+
});
672681
});
673682

674683
describe('fieldArray', () => {

0 commit comments

Comments
 (0)