Cross field validation in Angular2
Solution 1
You need to assign a custom validator to a complete form group to implement this. Something like this:
this.form = this.fb.group({
name: ['', Validators.required],
email: ['', Validators.required]
matchingPasswords: this.fb.group({
password: ['', Validators.required],
confirmPassword: ['', Validators.required]
}, {validator: this.matchValidator}) <--------
});
This way you will have access to all controls of the group and not only one... This can be accessed using the controls
property of the FormGroup. The FormGroup is provided when validation is triggered. For example:
matchValidator(group: FormGroup) {
var valid = false;
for (name in group.controls) {
var val = group.controls[name].value
(...)
}
if (valid) {
return null;
}
return {
mismatch: true
};
}
See this question for more details:
Solution 2
You can also use a custom directive validator to compare the fields.
In your html:
<div>
<label>Password</label>
<input type="password" name="password" [ngModel]="user.password"
required #password="ngModel">
<small [hidden]="password.valid || (password.pristine && !f.submitted)">
Password is required
</small>
</div>
<div>
<label>Retype password</label>
<input type="password" name="confirmPassword" [ngModel]="user.confirmPassword"
required validateEqual="password" #confirmPassword="ngModel">
<small [hidden]="confirmPassword.valid || (confirmPassword.pristine && !f.submitted)">
Password mismatch
</small>
</div>
And your directive:
import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
{ provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
]
})
export class EqualValidator implements Validator {
constructor( @Attribute('validateEqual') public validateEqual: string) {}
validate(c: AbstractControl): { [key: string]: any } {
// self value (e.g. retype password)
let v = c.value;
// control value (e.g. password)
let e = c.root.get(this.validateEqual);
// value not equal
if (e && v !== e.value) return {
validateEqual: false
}
return null;
}
}
Here is the complete solution in plunkr:
https://plnkr.co/edit/KgjSTj7VqbWMnRdYZdxM?p=preview
Solution 3
I haven't done this myself, but you could create ControlGroup
with two password fields and validate it. Controls have .valueChanges
property which is an observable and you can combine them and check for equality there.
Victor Savkin talks briefly about that exact case on Angular Air in this episode
Related videos on Youtube
Coaden
Leading development of a twitter sentiment analysis engine working with Python, NLTK (Natural Language Took Kit, PostgreSQL database, and the Django Web Framework. Also support and code several Android native apps.
Updated on July 09, 2022Comments
-
Coaden almost 2 years
I'm building an Angular2 client side application. I'm currently working on the membership components and integrating client side components with MVC6 vNext Identity v3. I have written custom Angular2 password validators as follows:
needsCapitalLetter(ctrl: Control): {[s: string]: boolean} { if(!ctrl.value.match(/[A-Z]/)) return {'needsCapitalLetter': true} return null; } needsLowerLetter(ctrl: Control): {[s: string]: boolean} { if(!ctrl.value.match(/[a-z]/)) return {'needsLowerLetter': true} return null; } needsNumber(ctrl: Control): {[s: string]: boolean} { if(!ctrl.value.match(/\d/)) return {'needsNumber': true} return null; } needsSpecialCharacter(ctrl: Control): {[s: string]: boolean} { if(!ctrl.value.match(/[^a-zA-Z\d]/)) return {'needsSpecialCharacter': true} return null; }
This work great, and I'm loving Angular2, but now I'm trying to write a validator that verifies that the "Confirm Password" is equal to the "Password". In order to do this, I need to be able to validate one field against the other. I can easily do this at the component level, and just check on blur, or on submit, or any number of other ways, but this bypasses the Angular2 ngForm validation system. I would very much like to figure out how to write an Angular2 Validator for a field that can check the value of another field, by passing in the name of the other field or something close to this. It seems this should be a capability as this would be a necessity in almost any complex business application UI.
-
Slava Fomin II almost 7 yearsPossible duplicate of Angular2 validator which relies on multiple form fields
-
-
Alexander Zanfir over 7 yearsThis seems like the right way until you try to send form.value over to your back-end, and you realize its sending your matching passwords object with both passwords. Any elegant solutions beyond deleting matching passwords and adding password before sending it over?
-
TexasJetter over 7 yearsThis solution is nice because it adds a global equal validator, unlike others that required re-writing code on each module. Note that the plunker code is different that what is posted here.
-
MarcS82 over 7 yearsHow do I define the password field in html? I found things like
<div ngFormControl="matchingPassword">
which seems not to be up to date anymore. -
eav about 7 yearsnice plunkr to understand. thanks i can use this one in my project.
-
Taras Budzyn about 7 yearsLittle update here. In the newest Angular 2
ControlGroup
was renamed toFormGroup
-
Kapil Soni over 3 yearssir i got 'validator' does not exist in type 'ValidatorFn error after use above?