FormBuilder group is deprecated with validator
Asked Answered
A

3

7

I have the simillar issue as here:

How do I resolve the error I am encountering using custom Validator syntax?

FormBuilder group is deprecated

I've read that Questions, but the issue still occurs in linter:

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. Note that AbstractControlOptions expects validators and asyncValidators to be valid validators. If you have custom validators, make sure their validation function parameter is AbstractControl and not a sub-class, such as FormGroup. These functions will be called with an object of type AbstractControl and that cannot be automatically downcast to a subclass, so TypeScript sees this as an error. For example, change the (group: FormGroup) => ValidationErrors|null signature to be (group: AbstractControl) => ValidationErrors|null. (deprecation)

And here is my formBuilder:

registerForm = this._fb.group({
        firstname: ["", [Validators.required]],
        lastname: ["", [Validators.required]],
        email: ["", [Validators.required, Validators.email]],
        password: ["", [PasswordValidator.strength]],
        confirmPassword: ["", [Validators.required]]
    }, {
        validator: PasswordValidator.confirmed("password", "confirmPassword")
    });

And my validator:

export class PasswordValidator {
    static confirmed = (controlName: string, matchingControlName: string) => {
        return (formGroup: FormGroup) => {
            const control = formGroup.controls[controlName];
            const matchingControl = formGroup.controls[matchingControlName];

            if (matchingControl.errors && !matchingControl.errors.confirmedValidator) {
                return null;
            }

            if (control.value !== matchingControl.value) {
                matchingControl.setErrors({ confirmedValidator: true });
                return ({ confirmedValidator: true });
            } else {
                matchingControl.setErrors(null);
                return null;
            }
        };
    }
}

Any idea why? I'm returning the proper object. :/

Alcoholize answered 20/1, 2021 at 17:23 Comment(10)
It is validators and not validatorDystrophy
fixed typo (removed brackets). But it's not the reasonAlcoholize
I mean the error is being thrown because of the line validator: PasswordValidator.confirmed("password", "confirmPassword")Dystrophy
Well yea, i'm aware of that but, how can I fix that?Alcoholize
Just add an s... validators: [PasswordValidator.confirmed("password", "confirmPassword")]Dystrophy
It's not solving the issue. It's one validator though.Alcoholize
Even if it is one or more validators. it has to be validators. with an s, and pass to it an array of one or more itemsDystrophy
That's not true.Alcoholize
You can re-read my answer here https://mcmap.net/q/1476519/-formbuilder-group-is-deprecated. interface AbstractControlOptions { validators?: ValidatorFn | ValidatorFn[] | null asyncValidators?: AsyncValidatorFn | AsyncValidatorFn[] | null updateOn?: 'change' | 'blur' | 'submit' } This is directly from the docs. The interface has validators, not validatorDystrophy
@OwenKelvin sorry, you've been right. Check my answer.Alcoholize
A
12

@OwenKelvin was partially right. It have to be validators instead validator in formBuilder, even though it's just one validator, sorry Owen again.

But the second problem was in validator. The function should receives AbstractControl instead FormGroup. So the following code is correct:

export class PasswordValidator {
    static confirmed = (controlName: string, matchingControlName: string) => {
        return (control: AbstractControl): ValidationErrors | null => {
            const input = control.get(controlName);
            const matchingInput = control.get(matchingControlName);

            if (input === null || matchingInput === null) {
                return null;
            }

            if (matchingInput?.errors && !matchingInput.errors.confirmedValidator) {
                return null;
            }

            if (input.value !== matchingInput.value) {
                matchingInput.setErrors({ confirmedValidator: true });
                return ({ confirmedValidator: true });
            } else {
                matchingInput.setErrors(null);
                return null;
            }
        };
    }
}
Alcoholize answered 21/1, 2021 at 8:25 Comment(1)
iam still having the exact same deprecation error after doing what u have suggested.Begorra
C
4

None of the proposed answers, also in the linked solutions, worked for me...This is how it worked for me:

This is how the validators, including the custom one, are invoked:

 this.form = this.fb.group(
      {
      Password:                  ['', { validators:[ Validators.required, Validators.minLength(4)]}],
      ConfirmPassword:           ['', { validators:[ Validators.required, Validators.minLength(4)]}]
      },
      {validators: this.matchingPasswords('Password', 'ConfirmPassword')}
    )

and this is the called validator (in this case placed in the same component)

matchingPasswords(Password: string, ConfirmPassword: string) {
    return (controls: AbstractControl) => {
      if (controls) {
        const Password = controls.get('Password')!.value;
        const ConfirmPassword = controls.get('ConfirmPassword')!.value;
        //console.log ("check what is passed to the validator", password, confirmPassword);
        if (Password !== ConfirmPassword) { 
          //this is an error set for a specific control which you can use in a mat-error
          controls.get('ConfirmPassword')?.setErrors({not_the_same: true});  
          //this is the returned error for the form normally used to disable a submit button
          return {mismatchedPassword: true}  
        }
      }
      return null;
    }
  }

   
  • No need (as I read in some threads) for the validation function to be in a separate module
  • No need to declare the validator call "as AbstractControlOptions". (which instead would prevent it from working)

To be noted:

  1. the call is to validators not validator
  2. values are extracted through the .get and need the ! to confirm we're sure they're not null
  3. the validator must return a ValidationError or null
Crossover answered 20/2, 2022 at 22:4 Comment(1)
This is the correct answer for Angular 12. Simply changing "validator:" to "validators:" made the deprecated message go away.Cheerio
G
2

Where you get the error?. I make a stackblitz with your code and I can not see it

BTW I don't like so much use setError to "put" an error to a control.

If you're not using mat-error, you can simply ask about form.errors.

If your'e using mat-error you can

Gussy answered 20/1, 2021 at 20:27 Comment(1)
You have no error because in your stackblitz you have used validators. Unfortunately the OP insists on using validator, singular because they have only 1 validatorDystrophy

© 2022 - 2024 — McMap. All rights reserved.