Custom Validator on reactive form for password and confirm password matching getting undefined parameters into Angular 4

后端 未结 9 1327
遥遥无期
遥遥无期 2020-12-01 00:47

I\'m trying to implement a custom validator to check if the password and password confirm are equal. The problem is that the validator is getting undefined password and conf

相关标签:
9条回答
  • 2020-12-01 01:13

    I would do the same as Shailesh Ladumor but adding the following line before returning in the validation function:

    c.get('confirm_password').setErrors({'noMatch': true});
    

    So that the validation function looks like this:

    passwordConfirming(c: AbstractControl): { invalid: boolean } {
        if (c.get('password').value !== c.get('confirm_password').value) {
            c.get('confirm_password').setErrors({'noMatch': true});
            return {invalid: true};
        }
    }
    

    This will not only set the hole userForm as an invalid form group, but it will also set confirm_password as an invalid form control.

    With this you can later call the following function in your template:

    public getPasswordConfirmationErrorMessage() {
    if (this.userForm.get('confirm_password').hasError('required')) {
      return 'You must retype your password';
    } else if (this.userForm.get('confirm_password').hasError('noMatch')) {
      return 'Passwords do not match';
    } else {
      return '';
    }
    

    }

    0 讨论(0)
  • 2020-12-01 01:15

    When you need to validate on more than one field, and you wish to declare validator at form creation time, FormGroup validator must be used. The main issue with form validator is that it attaches error to form and not to validating control, which leeds to some inconsistents in template. Here is reusable form validator wich attaches error to both form and control

    // in validators.ts file
    
    export function controlsEqual(
      controlName: string,
      equalToName: string,
      errorKey: string = controlName // here you can customize validation error key 
    ) {
    
      return (form: FormGroup) => {
        const control = form.get(controlName);
    
        if (control.value !== form.get(equalToName).value) {
          control.setErrors({ [errorKey]: true });
          return {
            [errorKey]: true
          }
        } else {
          control.setErrors(null);
          return null
        }
      }
    }
    
    // then you can use it like
      ngOnInit() {
        this.vmForm = this.fb.group({
          username: ['', [Validators.required, Validators.email]],
          password: ['', [
            Validators.required,
            Validators.pattern('[\\w\\d]+'),
            Validators.minLength(8)]],
          confirm: [''], // no need for any validators here
        }, { 
            // here we attach our form validator
            validators: controlsEqual('confirm', 'password')
          });
      }
    
    
    0 讨论(0)
  • 2020-12-01 01:17

    The issue is that you are mixing the reactive forms module with the input approach. This is causing you to get undefined when passing the values to the validator.

    You don't need to bind to the ng-model when using the reactive forms. Instead, you should access the value of the fields from the Instance of FormGroup.

    I do something like this in an app to validate the passwords match.

    public Credentials: FormGroup;
    
    ngOnInit() {
        this.Credentials = new FormGroup({});
        this.Credentials.addControl('Password', new FormControl('', [Validators.required]));
        this.Credentials.addControl('Confirmation', new FormControl(
            '', [Validators.compose(
                [Validators.required, this.validateAreEqual.bind(this)]
            )]
        ));
    }
    
    private validateAreEqual(fieldControl: FormControl) {
        return fieldControl.value === this.Credentials.get("Password").value ? null : {
            NotEqual: true
        };
    }
    

    Note that the validator expects a FormControl field as a parameter and it compares the value of the field to that of the value of the Password field of the Credentials FormGroup.

    In the HTML make sure to remove the ng-model.

    <input type="password" class="form-control" formControlName="confirmedPassword"  title="Please re-enter your password" >
    <!-- AND -->
    <input type="password" class="form-control" formControlName="password" title="Please enter your password">
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-01 01:17

    Please update FormGroup code like below in Angular5

     this.signUpForm = new FormGroup({
          'username': new FormControl(null, [Validators.required, Validators.minLength(6), Validators.maxLength(15)]),
          'email': new FormControl(null, [Validators.required, Validators.email, Validators.minLength(5)]),
          'password': new FormControl(null, [Validators.required]),
          'confirmedPassword': new FormControl(null, [Validators.required])
        }, this.pwdMatchValidator);
    

    Add pwdMatchValidator function in your component

    pwdMatchValidator(frm: FormGroup) {
        return frm.get('password').value === frm.get('confirmedPassword').value
           ? null : {'mismatch': true};
     }
    

    Add validation message in your template

    <span *ngIf="confirmedPassword.errors || signUpForm .errors?.mismatch">
                  Password doesn't match
                </span>
    

    Please find the below angular material working component.

    Component Templete Code password.component.html

     <form class="cahnge-pwd-form" (ngSubmit)="onSubmit()" name="passwordForm" [formGroup]="passwordForm" #formDir="ngForm">
          <div fxLayout='column'>
        <mat-form-field>
          <input matInput name="password" placeholder="Password" [type]="hide ? 'text' : 'password'" formControlName="password" required>
          <mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
          <mat-error *ngIf="password.invalid && (password.dirty || password.touched || isSubmit)">
            <span *ngIf="password.errors.required">
              Please enter a Password.
            </span>
            <span *ngIf="password.errors.maxlength">
              Please enter a Email no more than 16 characters.
            </span>
            <span *ngIf="password.errors.minlength">
              Please enter a password at least 6 characters.
            </span>
          </mat-error>
        </mat-form-field>
        <mat-form-field>
          <input matInput name="password" placeholder="Confirm Password" [type]="confirm_hide ? 'text' : 'password'" formControlName="confirm_password"
            required>
          <mat-icon matSuffix (click)="confirm_hide = !confirm_hide">{{confirm_hide ? 'visibility_off' : 'visibility'}}</mat-icon>
          <mat-error *ngIf="(confirm_password.invalid && (confirm_password.dirty || confirm_password.touched || isSubmit) || passwordForm.errors?.mismatch)">
            <span *ngIf="confirm_password.errors || passwordForm.errors?.mismatch">
              Password doesn't match
            </span>
          </mat-error>
        </mat-form-field>
        <div fxLayout='row' fxLayoutGap="10px">
          <button type="submit" mat-raised-button color="primary">Submit</button>
          <button type="button" (click)="formDir.resetForm(passwordForm)" mat-raised-button color="warn">Cancel</button>
        </div>
      </div>
    </form>
    

    Component Code : password.component.ts

    import { Component, OnInit, AfterViewInit } from '@angular/core';
    import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
    import { ToastrService } from 'ngx-toastr';
    import { Router, ActivatedRoute, ParamMap } from '@angular/router';
    import { PasswordService } from './password.service';
    import { PasswordValidation  } from './confirm';
    
    @Component({
      selector: 'app-password',
      templateUrl: './password.component.html',
      styleUrls: ['./password.component.css']
    })
    export class PasswordComponent implements OnInit {
      passwordForm: FormGroup;
      isSubmit: boolean;
      constructor(private router: Router, private passwordService: PasswordService, private toastrService: ToastrService, private route: ActivatedRoute) { }
      ngOnInit() {
        this.passwordForm = new FormGroup({
          'password': new FormControl('', [
            Validators.required,
            Validators.minLength(6),
            Validators.maxLength(16),
          ]),
          'confirm_password': new FormControl('', [
             Validators.required,
            Validators.minLength(6),
            Validators.maxLength(16),
          ]),
        }, this.pwdMatchValidator);
    
      }
     pwdMatchValidator(frm: FormGroup) {
        return frm.get('password').value === frm.get('confirm_password').value
           ? null : {'mismatch': true};
     }
    
      get password() { return this.passwordForm.get('password'); }
      get confirm_password() { return this.passwordForm.get('confirm_password'); }
    
      onSubmit(formvalue):boolean {
        this.isSubmit = true;
        if (this.passwordForm.invalid) {
          return false;
        } else {
          this.passwordService.updatePassword(this.passwordForm.value)
          .subscribe((res) => {
            if (res.status == 'success') {
              this.toastrService.success(res.msg);
              this.router.navigate(['/change-password']);
            }
          })
          return true;
        }
    
      }
    
    }
    
    0 讨论(0)
  • 2020-12-01 01:18

    When you're creating the validator, you're passing in the values of password and confirmedPassword, but changes in those values will not be reflected in the validator.

    The two options I see are:

    1. define your validator on the FormGroup, and look up the values from the two controls you want to compare; or
    2. since you're binding to this already, use this.password and this.confirmedPassword in your validator.
    0 讨论(0)
  • 2020-12-01 01:24

    import {AbstractControl, FormBuilder, FormGroup, Validators} from

    set your password input into the group and no need to use "ngModel".

    <div class="form-group row" formGroupName="passwords">
      <div class="form-group">
         <label for="password" class="control-label">Contraseña:</label>
         <input type="password" class="form-control" formControlName="password" title="Please enter your password">
         <p class="help-block" *ngIf="signUpForm.get('password').hasError('required') && signUpForm.get('password').touched">Debe ingresar una contraseña</p>
      </div>
      <div class="form-group">
         <label for="confirmedPassword" class="control-label">Confirmar Contraseña:</label>
         <input type="password" class="form-control" formControlName="confirmedPassword"  title="Please re-enter your password">
         <p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">Password must be required</p>
         <p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">password does not match</p>
      </div>
    

         buildForm(): void {
                this.userForm = this.formBuilder.group({
                    passwords: this.formBuilder.group({
                        password: ['', [Validators.required]],
                        confirm_password: ['', [Validators.required]],
                    }, {validator: this.passwordConfirming}),
    
                });
            }
    

    add this custom function for validate password and confirm password

      passwordConfirming(c: AbstractControl): { invalid: boolean } {
        if (c.get('password').value !== c.get('confirm_password').value) {
            return {invalid: true};
        }
    }
    

    Display error when password does not match

    <div style='color:#ff7355' *ngIf="userForm.get(['passwords','password']).value != userForm.get(['passwords','confirm_password']).value && userForm.get(['passwords','confirm_password']).value != null">
      Password does not match</div>
    
    0 讨论(0)
提交回复
热议问题