I can't seem to figure out why my custom validator is one step behind of the field value. Example: my input field has value 123 typed one by one. But my validator has value 12.
I can't correctly compare the values between two fields. This is the validator in a directive:
@Directive({
selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => PasswordValidationDirective),
multi: true
}
]
})
export class PasswordValidationDirective implements Validator {
@Input('first') first: string;
@Input('second') second: string;
constructor() {
}
public validate(ac: AbstractControl): { [key: string]: any } {
console.log(ac.root);
return null;
}
}
This is the html of the field:
<md-input-container class="full-width">
<input mdInput
type="password"
required
ngModel name="passwordConfirmation"
#passwordConfirmation="ngModel"
minlength="6"
maxlength="30"
pattern="(?=^.{6,30}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$"
validateEqual
first="password"
second="passwordConfirmation"
placeholder="{{'PASSWORD_RECOVERY.PASSWORD_CONFIRMATION' | translate}}">
<md-error *ngIf="passwordConfirmation.touched && passwordConfirmation.invalid">
<span *ngIf="passwordConfirmation.errors.required">
{{'PASSWORD_RECOVERY.FIELD_REQUIRED' | translate}}
</span>
<span *ngIf="passwordConfirmation.errors.minlength || passwordConfirmation.errors.maxlength">
{{'PASSWORD_RECOVERY.PASSWORD_LENGTH' | translate}}
</span>
<span *ngIf="passwordConfirmation.errors.pattern" class="p-md-error-multiline-div">
{{'PASSWORD_RECOVERY.FOR_A_SECURE_PASSWORD' | translate}}
</span>
</md-error>
</md-input-container>
Finally managed to find a solution! I decided to go with NgModelGroup
. Here's the directive:
@Directive({
selector: '[validateEqual][ngModelGroup]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => PasswordValidationDirective),
multi: true
}
]
})
export class PasswordValidationDirective implements Validator {
@Input('password') public password: string;
@Input('confirmation') public confirmation: string;
public validate(fg: FormGroup): { [key: string]: any } {
const fieldOne = fg.value[this.password];
const fieldTwo = fg.value[this.confirmation];
if (!fieldOne || !fieldTwo || fieldOne === fieldTwo ) {
return null;
}
return {valueEquals: false};
}
}
And here's the HTML:
<div ngModelGroup="passwordGroup"
#passwordGroup="ngModelGroup"
validateEqual
password="password"
confirmation="passwordConfirmation">
<div class="row">
<div class="col-xs-6">
<md-input-container class="full-width">
<input mdInput
type="password"
required
ngModel name="password"
#password="ngModel"
placeholder="{{'SIGNUP.PASSWORD' | translate}}">
</md-input-container>
</div>
<div class="col-xs-6">
<md-input-container class="full-width">
<input mdInput
type="password"
required
ngModel name="passwordConfirmation"
#passwordConfirmation="ngModel"
placeholder="{{'SIGNUP.RETYPE_PASSWORD' | translate}}">
</md-input-container>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<md-error *ngIf="passwordGroup.errors">
<span class="p-text-small-error">{{'SIGNUP.MATCH' | translate}}</span>
</md-error>
</div>
</div>
</div>
The important parts here are the directive itself and the incoming parameters, which can be modified to your liking.