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. :/

DiPix
  • 5,755
  • 15
  • 61
  • 108

3 Answers3

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;
            }
        };
    }
}
DiPix
  • 5,755
  • 15
  • 61
  • 108
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
Dharman
  • 30,962
  • 25
  • 85
  • 135
Nicola
  • 101
  • 1
  • 9
  • 1
    This is the correct answer for Angular 12. Simply changing "validator:" to "validators:" made the deprecated message go away. – dEf Feb 22 '22 at 18:34
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

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • 2
    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 validator – Owen Kelvin Jan 21 '21 at 03:15