Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 confirmedPassword parameters. How do I make this work. The function works cause if I change the condition to === instead of !== it throws the error correctly when the fields are the same. Does anyone know which is the error here?

signup.component.html

<div class="col-md-7 col-md-offset-1 col-sm-7">   <div class="block">     <div class="well">         <form (onSubmit)="onSubmit()" [formGroup]="signUpForm">           <div class="form-group">             <label for="username" class="control-label">Nombre de usuario:</label>             <input type="text" class="form-control" formControlName="username"  title="Please enter your username" placeholder="username">             <p class="help-block" *ngIf="signUpForm.get('username').hasError('required') && signUpForm.get('username').touched">El nombre de usuario es obligatorio</p>             <p class="help-block" *ngIf="signUpForm.get('username').hasError('minlength') && signUpForm.get('username').touched">El nombre de usuario debe tener al menos 6 caracteres</p>             <p class="help-block" *ngIf="signUpForm.get('username').hasError('maxlength') && signUpForm.get('username').touched">El nombre de usuario debe tener menos de 15 caracteres</p>           </div>           <div class="form-group">             <label for="email" class="control-label">E-mail:</label>             <input class="form-control" formControlName="email" title="Please enter your email" placeholder="[email protected]">             <p class="help-block" *ngIf="signUpForm.get('email').hasError('required') && signUpForm.get('email').touched">La dirección de email es obligatoria</p>             <p class="help-block" *ngIf="signUpForm.get('email').hasError('email') && signUpForm.get('email').touched">Debe ingresar una dirección de correo válida</p>           </div>           <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" [(ngModel)]="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" [(ngModel)]="confirmedPassword">             <p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">La confirmación de contraseña no puede estar vacía</p>             <p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">Las contraseñas no coinciden</p>           </div>           <button type="submit" class="btn btn-success" [disabled]="!signUpForm.valid">Registrarse</button>           <a routerLink="/signin" class="btn btn-default" style="">Ya tenes usuario? Logueate</a> {{ creationMessage }}         </form>        </div>    </div> </div> 

signup.component.ts

import { Component, OnInit, ViewChild, Input } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { CustomValidators } from '../../shared/custom-validators'; import { Observable } from 'rxjs/Observable';  @Component({   selector: 'app-signup',   templateUrl: './signup.component.html',   styleUrls: ['./signup.component.sass'] }) export class SignupComponent implements OnInit {    signUpForm: FormGroup;   user = {     username: '',     email: '',     password: ''   };   submitted = false;   @Input() password='';   @Input() confirmedPassword='';    constructor() { }    ngOnInit() {      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, CustomValidators.passwordsMatch(this.password,this.confirmedPassword).bind(this)])     });   }    onSubmit() {     if (this.signUpForm.valid) {       console.log(this.signUpForm.value);     }   }  } 

custom-validators.ts

    import { FormControl } from '@angular/forms';      export class CustomValidators{      public static passwordsMatch(password: string, confirmedPassword: string) {       return (control: FormControl) : { [s: string]: boolean } =>{        //getting undefined values for both variables        console.log(password,confirmedPassword);         //if I change this condition to === it throws the error if the  //  two fields are the same, so this part works         if (password !== confirmedPassword) {           return { 'passwordMismatch': true }         } else {           //it always gets here no matter what           return null;         }     }       }       } 
like image 917
Juan Avatar asked Jun 09 '17 05:06

Juan


2 Answers

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> 
like image 126
Shailesh Ladumor Avatar answered Sep 24 '22 19:09

Shailesh Ladumor


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!

like image 23
Daniel Ormeño Avatar answered Sep 23 '22 19:09

Daniel Ormeño