Please refer to this question regarding the Comparing fields in validator with Angular 2. Unfortunately Angular 2 changed a bit so that solution seems not working anymore. Here is my code:
import {IonicApp, Page, NavController, NavParams} from 'ionic/ionic'
import {Component} from 'angular2/core'
import {FORM_PROVIDERS, FormBuilder, Validators} from 'angular2/common'
import {ControlMessages} from '../../components/control-messages'
import {ValidationService} from '../../services/validation-service'
@Page({
templateUrl: 'build/pages/account/register.html',
directives: [ControlMessages]
})
export class RegisterPage {
constructor(nav: NavController, private builder: FormBuilder) {
this.nav = nav
this.registerForm = this.builder.group({
'name': ['', Validators.required],
'email': ['', Validators.compose([Validators.required, ValidationService.emailValidator])],
'password': ['', Validators.required],
'repeat': ['', this.customValidator]
}
)
}
register() {
alert(this.registerForm.value.password)
}
private customValidator(control) {
//console.log(this.registerForm.value.password)
//return {isEqual: control.value === this.registerForm.value.password}
return true
}
}
My html:
<ion-content class="account">
<ion-list padding>
<form [ngFormModel]='registerForm' (submit)='register()'>
<div class="centered">
<img class="logo" src="img/logo.png" alt="">
</div>
<div class="spacer" style="height: 20px;"></div>
<ion-input>
<ion-label floating>Name</ion-label>
<input type="text" ngControl='name' id='name'>
<control-messages control="name"></control-messages>
</ion-input>
<ion-input>
<ion-label floating>Email</ion-label>
<input type="email" ngControl='email' id='email'>
<control-messages control="email"></control-messages>
</ion-input>
<ion-input>
<ion-label floating>Password</ion-label>
<input type="password" ngControl='password' id='password' value="">
<control-messages control="password"></control-messages>
</ion-input>
<ion-input>
<ion-label floating>Confirm Password</ion-label>
<input type="password" ngControl='repeat' id='repeat'>
<control-messages control="repeat"></control-messages>
</ion-input>
<button class="calm" full type='submit' [disabled]='!registerForm.valid'>Register</button>
<ion-item style="background-color:transparent;border:none;">
<button class="text-button" clear item-right (click)="gotoLogin()">Have an account already, Login</button>
</ion-item>
</form>
</ion-list>
</ion-content>
But unfortunately, I can't access the password
value in my validating function. If I uncomment console.log(this.registerForm.value.password)
, then I get the following error message:
EXCEPTION: TypeError: Cannot read property 'value' of undefined
Any idea? Thanks.
I see several problems in your code. You try to use the this
keyword in the validator function and this doesn't correspond to the instance of the component. It's because you reference the function when setting it as a validator function.
Moreover the value associated with a control can be reached in the value
property.
That said, I think that the right way to validate your two fields together is to create a group and associate a validator in it:
import { FormBuilder, Validators } from '@angular/forms';
...
constructor(private fb: FormBuilder) { // <--- inject FormBuilder
this.createForm();
}
createForm() {
this.registerForm = this.fb.group({
'name' : ['', Validators.required],
'email': ['', [Validators.required, Validators.email] ],
'passwords': this.fb.group({
password: ['', Validators.required],
repeat: ['', Validators.required]
}, {validator: this.matchValidator})
});
}
This way you will have access to all controls of the group and not only one and don't need anymore to use the this
keyword... The group's form controls 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 anwer for more details:
Edit
To display the error, you can simply use the following:
<span *ngIf="!registerForm.passwords.valid" class="help-block text-danger">
<div *ngIf="registerForm.passwords?.errors?.mismatch">
The two passwords aren't the same
</div>
</span>
I've implemented a custom passwords match validator for Angular 4.
Besides checking if two values are matching, it also subscribes to changes from other control and re-validates when either of two controls is updated. Feel free to use it as a reference for your own implementation or just copy it directly.
Here's the link to the solution: https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30.
And here I'm providing a copy of the code:
import {FormControl} from '@angular/forms';
export function matchOtherValidator (otherControlName: string) {
let thisControl: FormControl;
let otherControl: FormControl;
return function matchOtherValidate (control: FormControl) {
if (!control.parent) {
return null;
}
// Initializing the validator.
if (!thisControl) {
thisControl = control;
otherControl = control.parent.get(otherControlName) as FormControl;
if (!otherControl) {
throw new Error('matchOtherValidator(): other control is not found in parent group');
}
otherControl.valueChanges.subscribe(() => {
thisControl.updateValueAndValidity();
});
}
if (!otherControl) {
return null;
}
if (otherControl.value !== thisControl.value) {
return {
matchOther: true
};
}
return null;
}
}
Here's how you can use it with reactive forms:
private constructForm () {
this.form = this.formBuilder.group({
email: ['', [
Validators.required,
Validators.email
]],
password: ['', Validators.required],
repeatPassword: ['', [
Validators.required,
matchOtherValidator('password')
]]
});
}
More up-to-date validators could be found here: moebius-mlm/ng-validators.
found much simpler solution. Not sure if this is the right way to do it but it works for me
<!-- PASSWORD -->
<ion-item [ngClass]="{'has-error': !signupForm.controls.password.valid && signupForm.controls.password.dirty}">
<ion-input formControlName="password" type="password" placeholder="{{ 'SIGNUP.PASSWORD' | translate }}" [(ngModel)]="registerCredentials.password"></ion-input>
</ion-item>
<!-- VERIFY PASSWORD -->
<ion-item [ngClass]="{'has-error': !signupForm.controls.verify.valid && signupForm.controls.verify.dirty}">
<ion-input formControlName="verify" [(ngModel)]="registerCredentials.verify" type="password" pattern="{{registerCredentials.password}}" placeholder="{{ 'SIGNUP.VERIFY' | translate }}"> </ion-input>
</ion-item>
See
pattern="{{registerCredentials.password}}"
Angular 4.3.3 solution!
You can do it using: [formGroup]
, formGroupName
, formControlName
in html and new FormGroup
, new FormControl
and custom areEqual
method in TS
reg.component.html
<div [formGroup]="userFormPassword">
<div>
<input formControlName="current_password" type="password" placeholder="Current Password">
</div>
<div formGroupName="passwords">
<input formControlName="new_password" type="password" placeholder="New Password">
</div>
<div formGroupName="passwords">
<input formControlName="repeat_new_password" type="password" class="form-control" placeholder="Repeat New Password">
<div class="input-error" *ngIf="
userFormPassword.controls['passwords'].errors &&
userFormPassword.controls['passwords'].errors.areEqual &&
userFormPassword.controls['passwords'].controls.repeat_new_password.touched &&
userFormPassword.controls['passwords'].controls.new_password.touched
">PASSWORDS do not match
</div>
</div>
</div>
reg.component.ts
export class HomeHeaderSettingsModalComponent implements OnInit {
userFormPassword: FormGroup;
// ...
static areEqual(c: AbstractControl): ValidationErrors | null {
const keys: string[] = Object.keys(c.value);
for (const i in keys) {
if (i !== '0' && c.value[ keys[ +i - 1 ] ] !== c.value[ keys[ i ] ]) {
return { areEqual: true };
}
}
}
ngOnInit() {
this.userFormPassword = new FormGroup({
'current_password': new FormControl(this.user.current_password, [
Validators.required,
]),
'passwords': new FormGroup({
'new_password': new FormControl(this.user.new_password, [
Validators.required
]),
'repeat_new_password': new FormControl(this.user.repeat_new_password, [
Validators.required
])
}, HomeHeaderSettingsModalComponent.areEqual)
});
}
}
Result:
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