I migrated my project to angular 11 and I noticed that the global validations that I added make FormBuilder.group
deprecated with the message:
group is deprecated: This api is not typesafe and can result in issues with Closure Compiler renaming. Use the `FormBuilder#group` overload with `AbstractControlOptions` instead.
so this is deprecated:
ingredientForm = this.fb.group({ ingredientType: ['', Validators.required], ingredientFlavor: [''], isMultiFlavor: [''], ingredientBrand: [''], ingredientName: [''], imageFile: [''] }, {validators: [ValidateThirdNumber.validate]});
and without the validators
option it's not.
my ValidateThirdNumber
validator:
class ValidateThirdNumber { static validate(control: AbstractControl): void { if (control) { const isMultiFlavor = control.get('isMultiFlavor')?.value; const ingredientFlavor = control.get('ingredientFlavor')?.value; const ingredientBrand = control.get('ingredientBrand')?.value; const ingredientName = control.get('ingredientName')?.value; if (isMultiFlavor && ingredientFlavor.trim().length === 0) { control.get('ingredientFlavor')?.setErrors({required_if: true}); } else { control.get('ingredientFlavor')?.setErrors(null); } if (!ingredientFlavor && !ingredientBrand && !ingredientName) { control.get('ingredientName')?.setErrors({required_at_least: true}); control.get('ingredientFlavor')?.setErrors({required_at_least: true}); control.get('ingredientBrand')?.setErrors({required_at_least: true}); } else { control.get('ingredientName')?.setErrors(null); control.get('ingredientFlavor')?.setErrors(null); control.get('ingredientBrand')?.setErrors(null); } if (ingredientBrand && ingredientName && ingredientName === ingredientBrand) { control.get('ingredientName')?.setErrors({not_the_same: true}); control.get('ingredientBrand')?.setErrors({not_the_same: true}); } } } }
how do I overload it with AbstractControlOptions ?
From the documentation we see two different lines with the group()
function
group(controlsConfig: { [key: string]: any; }, options?: AbstractControlOptions): FormGroup
AND
group(controlsConfig: { [key: string]: any; }, options: { [key: string]: any; }): FormGroup
The 2nd definition is what is deprecated
The difference in this lines is options?: AbstractControlOptions
and options: { [key: string]: any; }
To understand why angular is throwing this error we will now consider AbstractControlOptions
interface AbstractControlOptions { validators?: ValidatorFn | ValidatorFn[] | null asyncValidators?: AsyncValidatorFn | AsyncValidatorFn[] | null updateOn?: 'change' | 'blur' | 'submit' }
We continue to breakdown the problem by noting that the difference between this structure and your structure is ValidatorFn[]
interface ValidatorFn { (control: AbstractControl): ValidationErrors | null }
Overally, the error is thrown in your case because your Validator
function is expected to take a control and return ValidationErrors | null
. In the line validate(control: AbstractControl): void
, your code actually returns void
but expected to return a ValidationError | null
From the problem description, the solution is to simply modify the ValidatorFn
Ensure that your ValidatorFn
returns a ValidationError
or if no error returns null
From ValidationErrors defination
type ValidationErrors = { [key: string]: any; };
You will need to return a key value pair object e.g {required_if: true}
We can change your code by adding return statements as expected
class ValidateThirdNumber { static validate(control: AbstractControl): ValidationErrors | null { if (control) { const isMultiFlavor = control.get('isMultiFlavor')?.value; const ingredientFlavor = control.get('ingredientFlavor')?.value; const ingredientBrand = control.get('ingredientBrand')?.value; const ingredientName = control.get('ingredientName')?.value; if (isMultiFlavor && ingredientFlavor.trim().length === 0) { control.get('ingredientFlavor')?.setErrors({required_if: true}); return ({required_if: true}); } else { control.get('ingredientFlavor')?.setErrors(null); } if (!ingredientFlavor && !ingredientBrand && !ingredientName) { control.get('ingredientName')?.setErrors({required_at_least: true}); control.get('ingredientFlavor')?.setErrors({required_at_least: true}); control.get('ingredientBrand')?.setErrors({required_at_least: true}); return ({required_at_least: true}); } else { control.get('ingredientName')?.setErrors(null); control.get('ingredientFlavor')?.setErrors(null); control.get('ingredientBrand')?.setErrors(null); } if (ingredientBrand && ingredientName && ingredientName === ingredientBrand) { control.get('ingredientName')?.setErrors({not_the_same: true}); control.get('ingredientBrand')?.setErrors({not_the_same: true}); return ({not_the_same: true}); } } return null; } }
I also receive same error, I make following changes.
make sure that your validator function signature matches like this. (A function that receives a control and synchronously returns a map of validation errors if present, otherwise null.)
and you can change code in the form builder like this.
and in the formbuilder object pass above formOptions object like this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With