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; } } } }
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>
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!
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