I have a login component in my angular-CLI app. I have fields email and password. I created two custom validations => one for checking if the user exists, and other for checking if the password matches the user. I checked the working of built-in validators like a required field and valid email. They work fine. The problem is that my custom validators show errors only after the submission is called. The reactive form is not waiting for the custom async validators to resolve.
This is my code:
import {Component, OnInit} from '@angular/core';
import {FormGroup, FormBuilder, Validators} from '@angular/forms';
import {AuthService} from '../auth.service';
import {noUser, pwdMisMatch} from '../validators';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
form: FormGroup;
submitted = false;
returnUrl: string;
constructor(private formBuilder: FormBuilder, public authService: AuthService) {
this.form = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required],
},
{
validators: [noUser(authService, 'email'), pwdMisMatch(authService, 'email', 'password')]
, updateOn: 'blur'
}
);
}
ngOnInit() {
this.returnUrl = '/dashboard';
this.authService.logout();
}
get f() {
return this.form.controls;
}
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.form.invalid) {
return;
} else {
alert('Success');
}
}
}
This is my custom validators file:
import {FormGroup} from '@angular/forms';
import {AuthResponse, AuthService} from './auth.service';
export function MustMatch(controlName: string, matchingControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const matchingControl = formGroup.controls[matchingControlName];
if (matchingControl.errors && !matchingControl.errors.mustMatch) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
if (control.value !== matchingControl.value) {
matchingControl.setErrors({ mustMatch: true });
} else {
matchingControl.setErrors(null);
}
};
}
export function userExist(authservice: AuthService, controlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
if (control.errors && !control.errors.CheckUser) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authservice.checkUser(control.value).subscribe((res: AuthResponse) => {
if (res.ok) {
control.setErrors({ userExist: true });
} else {
control.setErrors(null);
}
});
};
}
export function noUser(authService: AuthService, controlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
if (control.errors && !control.errors.noUser) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authService.checkUser(control.value).subscribe((res: AuthResponse) => {
if (!res.ok) {
control.setErrors({ noUser: true });
} else {
control.setErrors(null);
}
});
};
}
export function pwdMisMatch(authService: AuthService, controlName: string, secureControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const secureControl = formGroup.controls[secureControlName];
if (control.errors || secureControl.errors && !secureControl.errors.pwdMisMatch) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authService.verifyPassword(control.value, secureControl.value).subscribe((res: AuthResponse) => {
if (!res.ok) {
secureControl.setErrors({ pwdMisMatch: true });
} else {
control.setErrors(null);
}
});
};
}
I tried this answer and the problem is not solved. Please help.
Update: my angular repo